From 47ce70080ae67faf6bb56034d7c754ce9cd15d4a Mon Sep 17 00:00:00 2001 From: flashduty-bot Date: Mon, 5 Oct 2026 08:26:04 +0000 Subject: [PATCH 1/3] =?UTF-8?q?docs(api):=20daily=20audit=202026-10-05=20?= =?UTF-8?q?=E2=80=94=20document=20the=20Monitors=20dashboard=20family?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fc-pgy 4100bf73 flipped all 17 /monit/dashboard/* registry rows plus /monit/folder/list from Auth "jwt" to "all", making them app_key-callable for the first time. Public registry rows 348 -> 366; the delta is exactly this commit. Adds 18 operations and 84 schemas to the monitors spec (EN + ZH) and to the consolidated reference copies, reconciled into the docs.json navigation and both api-catalog.mdx files (Monitors 23 -> 41 endpoints, total 338 -> 356). Schemas come from monit-webapi origin/main: types/dashboard/{contract, runtime,validate}.go, logic/logic_dashboard{,_runtime}.go, router/router_dashboard.go and router/router_folder.go. Purely additive: 0 deletions in every spec file under `git diff --minimal`. MD git log --oneline -1 git push --quiet -u origin "$BR" 2>&1 | tail -5 echo "push exit=$?" git rev-parse --short HEAD --- api-reference/monitors.openapi.en.json | 11996 +++++++--- api-reference/monitors.openapi.zh.json | 11926 ++++++--- api-reference/openapi.en.json | 29230 +++++++++++++--------- api-reference/openapi.zh.json | 29248 ++++++++++++++--------- docs.json | 60 + en/openapi/api-catalog.mdx | 32 +- zh/openapi/api-catalog.mdx | 32 +- 7 files changed, 52972 insertions(+), 29552 deletions(-) diff --git a/api-reference/monitors.openapi.en.json b/api-reference/monitors.openapi.en.json index bb59ed9fb..35165a825 100644 --- a/api-reference/monitors.openapi.en.json +++ b/api-reference/monitors.openapi.en.json @@ -32,6 +32,14 @@ { "name": "Monitors/Monitor utilities", "description": "Monitors service activation and data preview utilities." + }, + { + "name": "Monitors/Dashboards", + "description": "Create, search, version and run Monitors dashboards, and resolve their variables and queries." + }, + { + "name": "Monitors/Rule folders", + "description": "List the monitor folder tree that dashboards and alert rules are organised in." } ], "paths": { @@ -2395,3972 +2403,9790 @@ } } } - } - }, - "components": { - "securitySchemes": { - "AppKeyAuth": { - "type": "apiKey", - "in": "query", - "name": "app_key", - "description": "App key issued from the Flashduty console under Account → APP Keys. Required on every public API call. Keep it secret — it grants the same access as the owning account." - } }, - "responses": { - "BadRequest": { - "description": "Invalid request — usually a missing or malformed parameter.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - }, - "examples": { - "missingParameter": { - "value": { + "/monit/dashboard/create": { + "post": { + "operationId": "monit-dashboard-write-create", + "summary": "Create dashboard", + "description": "Create a dashboard from a full definition.", + "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 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.", + "href": "/en/api-reference/monitors/dashboards/monit-dashboard-write-create", + "metadata": { + "sidebarTitle": "Create dashboard" + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/DashboardResource" + } + } + } + ] + }, + "example": { "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", - "error": { - "code": "InvalidParameter", - "message": "The specified parameter is not valid." + "data": { + "dashboard_id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2101", + "schema_version": "dashboard.v1", + "revision": 7, + "folder_id": 12, + "folder_breadcrumb": [ + "Production", + "Checkout" + ], + "definition": { + "title": "Checkout service overview", + "description": "Traffic, errors and dependencies for the checkout service.", + "default_time_range": { + "from": "now-1h", + "to": "now" + }, + "refresh_interval": "1m", + "variables": [ + { + "kind": "custom", + "name": "env", + "label": "Environment", + "selection": { + "mode": "single", + "include_all": false + }, + "options": [ + { + "text": "Production", + "value": "prod" + }, + { + "text": "Staging", + "value": "staging" + } + ], + "default": { + "kind": "values", + "values": [ + "prod" + ] + } + } + ], + "tabs": [ + { + "id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2202", + "title": "Overview", + "description": "Golden signals.", + "top_panels": [], + "sections": [ + { + "id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2303", + "title": "Traffic", + "description": "Request rate and latency.", + "collapsed": false, + "panels": [ + { + "id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2404", + "title": "Request rate", + "grid": { + "x": 0, + "y": 0, + "w": 12, + "h": 8 + }, + "datasource_ref": { + "kind": "fixed", + "datasource_id": 10, + "datasource_type": "prometheus" + }, + "queries": [ + { + "ref_id": "A", + "legend_alias": "{{env}} requests", + "query": { + "mode": "range", + "expr": "sum(rate(http_requests_total{env=\"{{env}}\"}[5m]))", + "args": {}, + "min_step_seconds": 30 + } + } + ], + "viz_config": { + "kind": "time_series", + "options": {}, + "unit": "count_per_second", + "decimals": 2, + "threshold": { + "mode": "higher_is_worse", + "warning": 1000, + "critical": 2000 + } + } + } + ] + } + ] + } + ] + }, + "created_by": { + "id": 10023, + "name": "Ada Lovelace" + }, + "updated_by": { + "id": 10088, + "name": "Grace Hopper" + }, + "created_at": 1791000000, + "updated_at": 1791100800 } } } } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "429": { + "$ref": "#/components/responses/TooManyRequests" + }, + "500": { + "$ref": "#/components/responses/ServerError" } - } - }, - "Unauthorized": { - "description": "Missing or invalid app_key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - }, - "examples": { - "missingAppKey": { - "value": { - "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", - "error": { - "code": "Unauthorized", - "message": "You are unauthorized." - } + }, + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DashboardCreateRequest" + }, + "example": { + "dashboard_id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2101", + "schema_version": "dashboard.v1", + "folder_id": 12, + "definition": { + "title": "Checkout service overview", + "description": "Traffic, errors and dependencies for the checkout service.", + "default_time_range": { + "from": "now-1h", + "to": "now" + }, + "refresh_interval": "1m", + "variables": [ + { + "kind": "custom", + "name": "env", + "label": "Environment", + "selection": { + "mode": "single", + "include_all": false + }, + "options": [ + { + "text": "Production", + "value": "prod" + }, + { + "text": "Staging", + "value": "staging" + } + ], + "default": { + "kind": "values", + "values": [ + "prod" + ] + } + } + ], + "tabs": [ + { + "id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2202", + "title": "Overview", + "description": "Golden signals.", + "top_panels": [], + "sections": [ + { + "id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2303", + "title": "Traffic", + "description": "Request rate and latency.", + "collapsed": false, + "panels": [ + { + "id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2404", + "title": "Request rate", + "grid": { + "x": 0, + "y": 0, + "w": 12, + "h": 8 + }, + "datasource_ref": { + "kind": "fixed", + "datasource_id": 10, + "datasource_type": "prometheus" + }, + "queries": [ + { + "ref_id": "A", + "legend_alias": "{{env}} requests", + "query": { + "mode": "range", + "expr": "sum(rate(http_requests_total{env=\"{{env}}\"}[5m]))", + "args": {}, + "min_step_seconds": 30 + } + } + ], + "viz_config": { + "kind": "time_series", + "options": {}, + "unit": "count_per_second", + "decimals": 2, + "threshold": { + "mode": "higher_is_worse", + "warning": 1000, + "critical": 2000 + } + } + } + ] + } + ] + } + ] } } } } } - }, - "Forbidden": { - "description": "The app_key is valid but lacks permission for this operation.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - }, - "examples": { - "noEditPermission": { - "value": { + } + }, + "/monit/dashboard/get": { + "post": { + "operationId": "monit-dashboard-read-get", + "summary": "Get dashboard detail", + "description": "Fetch one dashboard with its full definition.", + "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- 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.", + "href": "/en/api-reference/monitors/dashboards/monit-dashboard-read-get", + "metadata": { + "sidebarTitle": "Get dashboard detail" + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/DashboardResource" + } + } + } + ] + }, + "example": { "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", - "error": { - "code": "AccessDenied", - "message": "Access Denied." + "data": { + "dashboard_id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2101", + "schema_version": "dashboard.v1", + "revision": 7, + "folder_id": 12, + "folder_breadcrumb": [ + "Production", + "Checkout" + ], + "definition": { + "title": "Checkout service overview", + "description": "Traffic, errors and dependencies for the checkout service.", + "default_time_range": { + "from": "now-1h", + "to": "now" + }, + "refresh_interval": "1m", + "variables": [ + { + "kind": "custom", + "name": "env", + "label": "Environment", + "selection": { + "mode": "single", + "include_all": false + }, + "options": [ + { + "text": "Production", + "value": "prod" + }, + { + "text": "Staging", + "value": "staging" + } + ], + "default": { + "kind": "values", + "values": [ + "prod" + ] + } + } + ], + "tabs": [ + { + "id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2202", + "title": "Overview", + "description": "Golden signals.", + "top_panels": [], + "sections": [ + { + "id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2303", + "title": "Traffic", + "description": "Request rate and latency.", + "collapsed": false, + "panels": [ + { + "id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2404", + "title": "Request rate", + "grid": { + "x": 0, + "y": 0, + "w": 12, + "h": 8 + }, + "datasource_ref": { + "kind": "fixed", + "datasource_id": 10, + "datasource_type": "prometheus" + }, + "queries": [ + { + "ref_id": "A", + "legend_alias": "{{env}} requests", + "query": { + "mode": "range", + "expr": "sum(rate(http_requests_total{env=\"{{env}}\"}[5m]))", + "args": {}, + "min_step_seconds": 30 + } + } + ], + "viz_config": { + "kind": "time_series", + "options": {}, + "unit": "count_per_second", + "decimals": 2, + "threshold": { + "mode": "higher_is_worse", + "warning": 1000, + "critical": 2000 + } + } + } + ] + } + ] + } + ] + }, + "created_by": { + "id": 10023, + "name": "Ada Lovelace" + }, + "updated_by": { + "id": 10088, + "name": "Grace Hopper" + }, + "created_at": 1791000000, + "updated_at": 1791100800 } } } } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "429": { + "$ref": "#/components/responses/TooManyRequests" + }, + "500": { + "$ref": "#/components/responses/ServerError" } - } - }, - "NotFound": { - "description": "The referenced resource does not exist or has been deleted. Note: Flashduty historically returns HTTP 400 with code `ResourceNotFound` for missing domain entities; a true 404 is reserved for unknown routes.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - }, - "examples": { - "resourceMissing": { - "value": { - "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", - "error": { - "code": "ResourceNotFound", - "message": "The resource you request is not found" - } - } + }, + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DashboardIDRequest" + }, + "example": { + "dashboard_id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2101" } } } } - }, - "TooManyRequests": { - "description": "Rate limit hit. Either the global API limit, a per-account limit, or a per-integration limit.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - }, - "examples": { - "rateLimited": { - "value": { + } + }, + "/monit/dashboard/update": { + "post": { + "operationId": "monit-dashboard-write-update", + "summary": "Update dashboard", + "description": "Replace a dashboard definition with compare-and-swap on the revision counter.", + "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 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.", + "href": "/en/api-reference/monitors/dashboards/monit-dashboard-write-update", + "metadata": { + "sidebarTitle": "Update dashboard" + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/DashboardUpdateOutput" + } + } + } + ] + }, + "example": { "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", - "error": { - "code": "RequestTooFrequently", - "message": "Request too frequently." + "data": { + "changed": true, + "resource": { + "dashboard_id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2101", + "schema_version": "dashboard.v1", + "revision": 7, + "folder_id": 12, + "folder_breadcrumb": [ + "Production", + "Checkout" + ], + "definition": { + "title": "Checkout service overview", + "description": "Traffic, errors and dependencies for the checkout service.", + "default_time_range": { + "from": "now-1h", + "to": "now" + }, + "refresh_interval": "1m", + "variables": [ + { + "kind": "custom", + "name": "env", + "label": "Environment", + "selection": { + "mode": "single", + "include_all": false + }, + "options": [ + { + "text": "Production", + "value": "prod" + }, + { + "text": "Staging", + "value": "staging" + } + ], + "default": { + "kind": "values", + "values": [ + "prod" + ] + } + } + ], + "tabs": [ + { + "id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2202", + "title": "Overview", + "description": "Golden signals.", + "top_panels": [], + "sections": [ + { + "id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2303", + "title": "Traffic", + "description": "Request rate and latency.", + "collapsed": false, + "panels": [ + { + "id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2404", + "title": "Request rate", + "grid": { + "x": 0, + "y": 0, + "w": 12, + "h": 8 + }, + "datasource_ref": { + "kind": "fixed", + "datasource_id": 10, + "datasource_type": "prometheus" + }, + "queries": [ + { + "ref_id": "A", + "legend_alias": "{{env}} requests", + "query": { + "mode": "range", + "expr": "sum(rate(http_requests_total{env=\"{{env}}\"}[5m]))", + "args": {}, + "min_step_seconds": 30 + } + } + ], + "viz_config": { + "kind": "time_series", + "options": {}, + "unit": "count_per_second", + "decimals": 2, + "threshold": { + "mode": "higher_is_worse", + "warning": 1000, + "critical": 2000 + } + } + } + ] + } + ] + } + ] + }, + "created_by": { + "id": 10023, + "name": "Ada Lovelace" + }, + "updated_by": { + "id": 10088, + "name": "Grace Hopper" + }, + "created_at": 1791000000, + "updated_at": 1791100800 + } } } } } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "429": { + "$ref": "#/components/responses/TooManyRequests" + }, + "500": { + "$ref": "#/components/responses/ServerError" } - } - }, - "ServerError": { - "description": "Unexpected server-side error. Include the request_id when reporting.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - }, - "examples": { - "internal": { - "value": { - "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", - "error": { - "code": "InternalError", - "message": "We encountered an internal error, and it has been reported. Please try again later." - } - } + }, + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DashboardUpdateRequest" + }, + "example": { + "dashboard_id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2101", + "schema_version": "dashboard.v1", + "expected_revision": 7, + "definition": { + "title": "Checkout service overview", + "description": "Traffic, errors and dependencies for the checkout service.", + "default_time_range": { + "from": "now-1h", + "to": "now" + }, + "refresh_interval": "1m", + "variables": [ + { + "kind": "custom", + "name": "env", + "label": "Environment", + "selection": { + "mode": "single", + "include_all": false + }, + "options": [ + { + "text": "Production", + "value": "prod" + }, + { + "text": "Staging", + "value": "staging" + } + ], + "default": { + "kind": "values", + "values": [ + "prod" + ] + } + } + ], + "tabs": [ + { + "id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2202", + "title": "Overview", + "description": "Golden signals.", + "top_panels": [], + "sections": [ + { + "id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2303", + "title": "Traffic", + "description": "Request rate and latency.", + "collapsed": false, + "panels": [ + { + "id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2404", + "title": "Request rate", + "grid": { + "x": 0, + "y": 0, + "w": 12, + "h": 8 + }, + "datasource_ref": { + "kind": "fixed", + "datasource_id": 10, + "datasource_type": "prometheus" + }, + "queries": [ + { + "ref_id": "A", + "legend_alias": "{{env}} requests", + "query": { + "mode": "range", + "expr": "sum(rate(http_requests_total{env=\"{{env}}\"}[5m]))", + "args": {}, + "min_step_seconds": 30 + } + } + ], + "viz_config": { + "kind": "time_series", + "options": {}, + "unit": "count_per_second", + "decimals": 2, + "threshold": { + "mode": "higher_is_worse", + "warning": 1000, + "critical": 2000 + } + } + } + ] + } + ] + } + ] + }, + "message": "Split the latency panel" } } } } - }, - "ServiceUnavailable": { - "description": "The service is temporarily unavailable. Include the request_id when reporting.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - }, - "examples": { - "serviceUnavailable": { - "value": { + } + }, + "/monit/dashboard/move": { + "post": { + "operationId": "monit-dashboard-write-move", + "summary": "Move dashboard", + "description": "Move a dashboard to another folder without changing its definition.", + "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- 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.", + "href": "/en/api-reference/monitors/dashboards/monit-dashboard-write-move", + "metadata": { + "sidebarTitle": "Move dashboard" + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/DashboardUpdateOutput" + } + } + } + ] + }, + "example": { "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", - "error": { - "code": "ServiceUnavailable", - "message": "service temporarily unavailable" + "data": { + "changed": true, + "resource": { + "dashboard_id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2101", + "schema_version": "dashboard.v1", + "revision": 7, + "folder_id": 12, + "folder_breadcrumb": [ + "Production", + "Checkout" + ], + "definition": { + "title": "Checkout service overview", + "description": "Traffic, errors and dependencies for the checkout service.", + "default_time_range": { + "from": "now-1h", + "to": "now" + }, + "refresh_interval": "1m", + "variables": [ + { + "kind": "custom", + "name": "env", + "label": "Environment", + "selection": { + "mode": "single", + "include_all": false + }, + "options": [ + { + "text": "Production", + "value": "prod" + }, + { + "text": "Staging", + "value": "staging" + } + ], + "default": { + "kind": "values", + "values": [ + "prod" + ] + } + } + ], + "tabs": [ + { + "id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2202", + "title": "Overview", + "description": "Golden signals.", + "top_panels": [], + "sections": [ + { + "id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2303", + "title": "Traffic", + "description": "Request rate and latency.", + "collapsed": false, + "panels": [ + { + "id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2404", + "title": "Request rate", + "grid": { + "x": 0, + "y": 0, + "w": 12, + "h": 8 + }, + "datasource_ref": { + "kind": "fixed", + "datasource_id": 10, + "datasource_type": "prometheus" + }, + "queries": [ + { + "ref_id": "A", + "legend_alias": "{{env}} requests", + "query": { + "mode": "range", + "expr": "sum(rate(http_requests_total{env=\"{{env}}\"}[5m]))", + "args": {}, + "min_step_seconds": 30 + } + } + ], + "viz_config": { + "kind": "time_series", + "options": {}, + "unit": "count_per_second", + "decimals": 2, + "threshold": { + "mode": "higher_is_worse", + "warning": 1000, + "critical": 2000 + } + } + } + ] + } + ] + } + ] + }, + "created_by": { + "id": 10023, + "name": "Ada Lovelace" + }, + "updated_by": { + "id": 10088, + "name": "Grace Hopper" + }, + "created_at": 1791000000, + "updated_at": 1791100800 + } } } } } - } - } - } - }, - "schemas": { - "AlertRule": { - "type": "object", - "description": "Full alert rule configuration.", - "properties": { - "id": { - "type": "integer", - "format": "uint64", - "description": "Rule ID. Required for update; omit for create (assigned by the server)." - }, - "account_id": { - "type": "integer", - "format": "uint64", - "description": "Account ID. Filled by the server from the authenticated identity; do not provide." - }, - "folder_id": { - "type": "integer", - "format": "uint64", - "description": "ID of the folder the rule belongs to. Obtainable via `POST /monit/folder/list`." - }, - "name": { - "type": "string", - "description": "Rule name. Must be unique within the same folder." - }, - "labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom labels." - }, - "ds_type": { - "type": "string", - "description": "Datasource type identifier (e.g. `prometheus`, `elasticsearch`)." - }, - "ds_list": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Data source name patterns (supports wildcards). At least one of `ds_list` / `ds_ids` must be non-empty; the two are merged to decide which datasources the rule monitors." }, - "ds_ids": { - "type": "array", - "items": { - "type": "integer", - "format": "uint64" - }, - "description": "Datasource IDs, merged with `ds_list` to decide which datasources the rule monitors; IDs survive datasource renames. At least one of `ds_list` and `ds_ids` must be provided." + "400": { + "$ref": "#/components/responses/BadRequest" }, - "enabled": { - "type": "boolean", - "description": "Whether the rule is enabled. Updating to `false` makes the server clean up the rule's active alerts." + "401": { + "$ref": "#/components/responses/Unauthorized" }, - "debug_log_enabled": { - "type": "boolean", - "description": "Whether to enable debug logging; the edge emits detailed evaluation logs, useful for troubleshooting rules that do not trigger as expected." + "403": { + "$ref": "#/components/responses/Forbidden" }, - "rule_configs": { - "$ref": "#/components/schemas/RuleConfigs", - "description": "Check configuration: query list plus trigger/recovery conditions. Structure see `RuleConfigs`." + "429": { + "$ref": "#/components/responses/TooManyRequests" }, - "cron_pattern": { - "type": "string", - "description": "Schedule expression: a 6-field cron (with seconds) or an `@every 30s` interval descriptor. Must not start with `CRON_TZ=` or `TZ=`; use the `timezone` field instead." - }, - "timezone": { - "type": "string", - "description": "Timezone in which the rule executes. Determines how the cron schedule and effective time windows are interpreted. Only IANA timezone names are accepted (e.g. `Asia/Shanghai`, `UTC`, `Europe/London`); shortcuts and offsets such as `Local`, `UTC+8`, or `CST` are rejected. Treated as `Asia/Shanghai` if empty.", - "default": "Asia/Shanghai" - }, - "delay_seconds": { - "type": "integer", - "description": "Seconds to shift the evaluation query window backward, compensating for data ingestion latency." - }, - "enabled_times": { - "type": "array", - "description": "Time windows when the rule is active. Defaults to all days from 00:00 to 23:59 when omitted or empty.", - "default": [ - { - "days": [ - 1, - 2, - 3, - 4, - 5, - 6, - 0 - ], - "stime": "00:00", - "etime": "23:59" + "500": { + "$ref": "#/components/responses/ServerError" + } + }, + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DashboardMoveRequest" + }, + "example": { + "dashboard_id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2101", + "expected_revision": 7, + "folder_id": 15 } - ], - "items": { - "type": "object", - "properties": { - "days": { - "type": "array", - "items": { - "type": "integer" - }, - "description": "Days of week (0=Sunday)." - }, - "stime": { - "type": "string", - "description": "Start time, e.g. `09:00`." + } + } + } + } + }, + "/monit/dashboard/delete": { + "post": { + "operationId": "monit-dashboard-write-delete", + "summary": "Delete dashboard", + "description": "Move a dashboard to the trash.", + "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.", + "href": "/en/api-reference/monitors/dashboards/monit-dashboard-write-delete", + "metadata": { + "sidebarTitle": "Delete dashboard" + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/DashboardDeleteOutput" + } + } + } + ] }, - "etime": { - "type": "string", - "description": "End time, e.g. `18:00`." + "example": { + "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", + "data": { + "dashboard_id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2101", + "revision": 8 + } } } } }, - "annotations": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Annotation key-value pairs delivered with alert events; keys must not start with `$` (reserved for query fields)." - }, - "description_type": { - "type": "string", - "enum": [ - "text", - "markdown" - ], - "default": "text", - "description": "Format for the description. Defaults to `text` when omitted or empty. `text` = plain text; `markdown` = Markdown, rendered as Markdown in alert details." - }, - "description": { - "type": "string", - "description": "Rule description, in Markdown." + "400": { + "$ref": "#/components/responses/BadRequest" }, - "channel_ids": { - "type": "array", - "items": { - "type": "integer", - "format": "uint64" - }, - "description": "Channel IDs to send alerts to." + "401": { + "$ref": "#/components/responses/Unauthorized" }, - "repeat_interval": { - "type": "integer", - "format": "int64", - "description": "Notification repeat interval in seconds." + "403": { + "$ref": "#/components/responses/Forbidden" }, - "repeat_total": { - "type": "integer", - "format": "int64", - "description": "Max number of repeat notifications." + "429": { + "$ref": "#/components/responses/TooManyRequests" }, - "creator_id": { - "type": "integer", - "format": "uint64", - "description": "Creator user ID. Filled by the server from the current user; do not provide." + "500": { + "$ref": "#/components/responses/ServerError" + } + }, + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DashboardDeleteRequest" + }, + "example": { + "dashboard_id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2101", + "expected_revision": 7 + } + } + } + } + } + }, + "/monit/dashboard/restore": { + "post": { + "operationId": "monit-dashboard-write-restore", + "summary": "Restore dashboard", + "description": "Bring a trashed dashboard back, optionally into a different folder.", + "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- 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.", + "href": "/en/api-reference/monitors/dashboards/monit-dashboard-write-restore", + "metadata": { + "sidebarTitle": "Restore dashboard" + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/DashboardResource" + } + } + } + ] + }, + "example": { + "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", + "data": { + "dashboard_id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2101", + "schema_version": "dashboard.v1", + "revision": 7, + "folder_id": 12, + "folder_breadcrumb": [ + "Production", + "Checkout" + ], + "definition": { + "title": "Checkout service overview", + "description": "Traffic, errors and dependencies for the checkout service.", + "default_time_range": { + "from": "now-1h", + "to": "now" + }, + "refresh_interval": "1m", + "variables": [ + { + "kind": "custom", + "name": "env", + "label": "Environment", + "selection": { + "mode": "single", + "include_all": false + }, + "options": [ + { + "text": "Production", + "value": "prod" + }, + { + "text": "Staging", + "value": "staging" + } + ], + "default": { + "kind": "values", + "values": [ + "prod" + ] + } + } + ], + "tabs": [ + { + "id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2202", + "title": "Overview", + "description": "Golden signals.", + "top_panels": [], + "sections": [ + { + "id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2303", + "title": "Traffic", + "description": "Request rate and latency.", + "collapsed": false, + "panels": [ + { + "id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2404", + "title": "Request rate", + "grid": { + "x": 0, + "y": 0, + "w": 12, + "h": 8 + }, + "datasource_ref": { + "kind": "fixed", + "datasource_id": 10, + "datasource_type": "prometheus" + }, + "queries": [ + { + "ref_id": "A", + "legend_alias": "{{env}} requests", + "query": { + "mode": "range", + "expr": "sum(rate(http_requests_total{env=\"{{env}}\"}[5m]))", + "args": {}, + "min_step_seconds": 30 + } + } + ], + "viz_config": { + "kind": "time_series", + "options": {}, + "unit": "count_per_second", + "decimals": 2, + "threshold": { + "mode": "higher_is_worse", + "warning": 1000, + "critical": 2000 + } + } + } + ] + } + ] + } + ] + }, + "created_by": { + "id": 10023, + "name": "Ada Lovelace" + }, + "updated_by": { + "id": 10088, + "name": "Grace Hopper" + }, + "created_at": 1791000000, + "updated_at": 1791100800 + } + } + } + } }, - "creator_name": { - "type": "string", - "description": "Creator name. Filled by the server; do not provide." + "400": { + "$ref": "#/components/responses/BadRequest" }, - "updater_id": { - "type": "integer", - "format": "uint64", - "description": "Last updater user ID. Filled by the server; do not provide." + "401": { + "$ref": "#/components/responses/Unauthorized" }, - "updater_name": { - "type": "string", - "description": "Last updater name. Filled by the server; do not provide." + "403": { + "$ref": "#/components/responses/Forbidden" }, - "created_at": { - "type": "integer", - "format": "int64", - "description": "Creation time as a Unix timestamp in seconds. Generated by the server; do not provide." + "429": { + "$ref": "#/components/responses/TooManyRequests" }, - "updated_at": { - "type": "integer", - "format": "int64", - "description": "Last update time as a Unix timestamp in seconds. Generated by the server; do not provide." + "500": { + "$ref": "#/components/responses/ServerError" } }, - "required": [ - "folder_id", - "name", - "ds_type", - "cron_pattern", - "rule_configs" - ] - }, - "AlertRuleAudit": { - "type": "object", - "description": "An audit record capturing a rule snapshot at a point in time.", - "required": [ - "id", - "account_id", - "alert_rule_id", - "action", - "creator_id", - "creator_name", - "created_at" - ], - "properties": { - "id": { - "type": "integer", - "format": "uint64", - "description": "Audit record ID." - }, - "account_id": { - "type": "integer", - "format": "uint64", - "description": "ID of the account that owns the rule." - }, - "alert_rule_id": { - "type": "integer", - "format": "uint64", - "description": "ID of the alert rule this record belongs to." - }, - "action": { - "type": "string", - "description": "Action performed: `create` = rule created; `update` = rule updated (covers full updates, field-batch updates, imports and moves).", - "enum": [ - "create", - "update" - ] - }, + "requestBody": { + "required": true, "content": { - "type": "string", - "description": "JSON string of the full rule snapshot at audit time. Populated on `/monit/rule/audit/detail`, omitted on list responses." - }, - "creator_id": { - "type": "integer", - "format": "uint64", - "description": "ID of the user who made this change (taken from the rule's `updater_id` at change time)." - }, - "creator_name": { - "type": "string", - "description": "Name of the user who made this change (taken from the rule's `updater_name` at change time)." - }, - "created_at": { - "type": "integer", - "format": "int64", - "description": "When this audit record was produced, as a Unix timestamp in seconds; equals the rule's `updated_at` at change time." + "application/json": { + "schema": { + "$ref": "#/components/schemas/DashboardRestoreRequest" + }, + "example": { + "dashboard_id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2101", + "expected_revision": 8, + "folder_id": 15 + } + } } } - }, - "AlertRuleBasic": { - "type": "object", - "description": "Basic alert rule information for list views.", - "required": [ - "id", - "account_id", - "folder_id", - "name", - "ds_type", - "enabled", - "debug_log_enabled", - "cron_pattern", - "delay_seconds", - "creator_id", - "creator_name", - "updater_id", - "updater_name", - "created_at", - "updated_at", - "triggered", - "labels", - "timezone", - "active_alert_count" + } + }, + "/monit/dashboard/list": { + "post": { + "operationId": "monit-dashboard-read-list", + "summary": "List dashboards", + "description": "List the dashboards in one folder.", + "tags": [ + "Monitors/Dashboards" ], - "properties": { - "id": { - "type": "integer", - "format": "uint64", - "description": "Unique rule ID." - }, - "account_id": { - "type": "integer", - "format": "uint64", - "description": "Account ID." - }, - "folder_id": { - "type": "integer", - "format": "uint64", - "description": "Folder ID." - }, - "name": { - "type": "string", - "description": "Rule name." - }, - "labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom labels." - }, - "ds_type": { - "type": "string", - "description": "Data source type, e.g. `prometheus`." + "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.", + "href": "/en/api-reference/monitors/dashboards/monit-dashboard-read-list", + "metadata": { + "sidebarTitle": "List dashboards" + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/DashboardListOutput" + } + } + } + ] + }, + "example": { + "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", + "data": { + "items": [ + { + "dashboard_id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2101", + "folder_id": 12, + "folder_breadcrumb": [ + "Production", + "Checkout" + ], + "title": "Checkout service overview", + "description": "Traffic, errors and dependencies for the checkout service.", + "revision": 7, + "updated_by": { + "id": 10088, + "name": "Grace Hopper" + }, + "updated_at": 1791100800 + } + ], + "total": 1 + } + } + } + } }, - "enabled": { - "type": "boolean", - "description": "Whether the rule is enabled." + "400": { + "$ref": "#/components/responses/BadRequest" }, - "debug_log_enabled": { - "type": "boolean", - "description": "Whether debug logging is enabled." + "401": { + "$ref": "#/components/responses/Unauthorized" }, - "cron_pattern": { - "type": "string", - "description": "Schedule expression: a 6-field cron with seconds, e.g. `0 * * * * *`, or an `@every 30s` interval descriptor. Must not start with `CRON_TZ=` or `TZ=`; use the `timezone` field instead." + "403": { + "$ref": "#/components/responses/Forbidden" }, - "timezone": { - "type": "string", - "description": "Timezone in which the rule executes. Determines how the cron schedule and effective time windows are interpreted. Only IANA timezone names are accepted (e.g. `Asia/Shanghai`, `UTC`, `Europe/London`); shortcuts and offsets such as `Local`, `UTC+8`, or `CST` are rejected. Treated as `Asia/Shanghai` if empty.", - "default": "Asia/Shanghai" + "404": { + "$ref": "#/components/responses/NotFound" }, - "delay_seconds": { - "type": "integer", - "description": "Evaluation delay in seconds." + "429": { + "$ref": "#/components/responses/TooManyRequests" }, - "creator_id": { - "type": "integer", - "format": "uint64", - "description": "ID of the user who created the rule." + "500": { + "$ref": "#/components/responses/ServerError" + } + }, + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DashboardListRequest" + }, + "example": { + "folder_id": 12, + "query": "checkout", + "sort": [ + { + "field": "updated_at", + "direction": "desc" + } + ], + "p": 1, + "limit": 20 + } + } + } + } + } + }, + "/monit/dashboard/search": { + "post": { + "operationId": "monit-dashboard-read-search", + "summary": "Search dashboards", + "description": "Search dashboards across every readable folder.", + "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- `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`.", + "href": "/en/api-reference/monitors/dashboards/monit-dashboard-read-search", + "metadata": { + "sidebarTitle": "Search dashboards" + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/DashboardListOutput" + } + } + } + ] + }, + "example": { + "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", + "data": { + "items": [ + { + "dashboard_id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2101", + "folder_id": 12, + "folder_breadcrumb": [ + "Production", + "Checkout" + ], + "title": "Checkout service overview", + "description": "Traffic, errors and dependencies for the checkout service.", + "revision": 7, + "updated_by": { + "id": 10088, + "name": "Grace Hopper" + }, + "updated_at": 1791100800 + } + ], + "total": 1 + } + } + } + } }, - "creator_name": { - "type": "string", - "description": "Name of the user who created the rule." + "400": { + "$ref": "#/components/responses/BadRequest" }, - "updater_id": { - "type": "integer", - "format": "uint64", - "description": "ID of the user who last modified the rule." + "401": { + "$ref": "#/components/responses/Unauthorized" }, - "updater_name": { - "type": "string", - "description": "Name of the user who last modified the rule." + "403": { + "$ref": "#/components/responses/Forbidden" }, - "created_at": { - "type": "integer", - "format": "int64", - "description": "Creation time, as a Unix timestamp in seconds." + "404": { + "$ref": "#/components/responses/NotFound" }, - "updated_at": { - "type": "integer", - "format": "int64", - "description": "Last modification time, as a Unix timestamp in seconds." + "429": { + "$ref": "#/components/responses/TooManyRequests" }, - "triggered": { - "type": "boolean", - "description": "True if the rule currently has active alerts." - }, - "active_alert_count": { - "type": "integer", - "format": "int64", - "description": "Number of currently active (unrecovered) alerts fired by this rule. `triggered` equals `active_alert_count > 0`." - }, - "runtime_state": { - "type": "string", - "enum": [ - "disabled", - "offline", - "abnormal", - "stale", - "no_datasource", - "config_pending", - "waiting", - "normal" - ], - "description": "Runtime evaluation state, derived from edge heartbeats and the edge-reported rule status. Omitted when the state is unavailable.\n\n| Value | Meaning |\n|---|---|\n| `disabled` | The rule is disabled. |\n| `offline` | The edge instance or cluster owning this rule is offline. |\n| `abnormal` | The edge reports evaluation errors. |\n| `stale` | The edge's runtime status report is outdated. |\n| `no_datasource` | No datasource currently matches the rule's `ds_list` / `ds_ids`. |\n| `config_pending` | The latest rule config has not been delivered to the edge yet. |\n| `waiting` | Enabled, but the edge has not reported runtime status yet. |\n| `normal` | Evaluating normally. |" + "500": { + "$ref": "#/components/responses/ServerError" } - } - }, - "AlertRuleCounter": { - "type": "object", - "description": "One historical snapshot of the account's alert rule total.", - "required": [ - "id", - "account_id", - "num", - "clock" - ], - "properties": { - "id": { - "type": "integer", - "format": "uint64", - "description": "ID of this snapshot record." - }, - "account_id": { - "type": "integer", - "format": "uint64", - "description": "ID of the account this snapshot belongs to." - }, - "num": { - "type": "integer", - "format": "int64", - "description": "Rule count at the sample time." - }, - "clock": { - "type": "integer", - "format": "int64", - "description": "Sample timestamp, Unix epoch seconds." + }, + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DashboardSearchRequest" + }, + "example": { + "query": "checkout latency", + "sort": [ + { + "field": "title", + "direction": "asc" + } + ], + "p": 1, + "limit": 20 + } + } } } - }, - "AlertRuleExport": { - "type": "object", - "description": "Portable alert rule representation for import/export. Omits identifying fields like `id`, `account_id`, and audit metadata.", - "required": [ - "name", - "ds_type", - "enabled", - "debug_log_enabled", - "cron_pattern" + } + }, + "/monit/dashboard/trash/list": { + "post": { + "operationId": "monit-dashboard-trash-read-list", + "summary": "List trashed dashboards", + "description": "List deleted dashboards still inside the 30-day retention window.", + "tags": [ + "Monitors/Dashboards" ], - "properties": { - "name": { - "type": "string", - "description": "Rule name, up to 128 characters when imported." - }, - "labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom label key-value pairs attached to alert events produced by this rule." - }, - "ds_type": { - "type": "string", - "description": "Datasource type ident, e.g. `prometheus`; must be a datasource type (`ident`) that exists in the import target environment." - }, - "ds_list": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Datasource name list with wildcard support; merged with `ds_ids` to decide which datasources the rule monitors — must be maintained by hand if a datasource is renamed." + "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.", + "href": "/en/api-reference/monitors/dashboards/monit-dashboard-trash-read-list", + "metadata": { + "sidebarTitle": "List trashed dashboards" + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/DashboardTrashListOutput" + } + } + } + ] + }, + "example": { + "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", + "data": { + "items": [ + { + "dashboard_id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2101", + "folder_id": 12, + "folder_breadcrumb": [ + "Production", + "Checkout" + ], + "title": "Checkout service overview", + "description": "Traffic, errors and dependencies for the checkout service.", + "revision": 8, + "deleted_by": { + "id": 10088, + "name": "Grace Hopper" + }, + "deleted_at": 1791101000 + } + ], + "total": 1 + } + } + } + } }, - "ds_ids": { - "type": "array", - "items": { - "type": "integer", - "format": "uint64" - }, - "description": "Datasource ID list, merged with `ds_list`; references by ID and is therefore immune to datasource renames." + "400": { + "$ref": "#/components/responses/BadRequest" }, - "enabled": { - "type": "boolean", - "description": "Whether the rule is enabled; rules imported as disabled are not evaluated." + "401": { + "$ref": "#/components/responses/Unauthorized" }, - "debug_log_enabled": { - "type": "boolean", - "description": "Whether to emit debug logs for this rule's evaluations; enable when troubleshooting." + "403": { + "$ref": "#/components/responses/Forbidden" }, - "rule_configs": { - "$ref": "#/components/schemas/RuleConfigs" + "429": { + "$ref": "#/components/responses/TooManyRequests" }, - "cron_pattern": { - "type": "string", - "description": "Evaluation schedule as a 6-field cron expression (seconds included) or `@every ` (an integral number of seconds, at least 1s); `CRON_TZ=`/`TZ=` prefixes are rejected — set the timezone in `timezone` instead." + "500": { + "$ref": "#/components/responses/ServerError" + } + }, + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DashboardTrashListRequest" + }, + "example": { + "sort": [ + { + "field": "deleted_at", + "direction": "desc" + } + ], + "p": 1, + "limit": 20 + } + } + } + } + } + }, + "/monit/dashboard/revisions/list": { + "post": { + "operationId": "monit-dashboard-revision-read-list", + "summary": "List dashboard revisions", + "description": "List a dashboard's revision history, newest first.", + "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- At most 20 revisions are retained, including the current one; older ones are dropped as new revisions land.", + "href": "/en/api-reference/monitors/dashboards/monit-dashboard-revision-read-list", + "metadata": { + "sidebarTitle": "List dashboard revisions" + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/DashboardRevisionListOutput" + } + } + } + ] + }, + "example": { + "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", + "data": { + "items": [ + { + "dashboard_id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2101", + "revision": 7, + "folder_id": 12, + "message": "Split the latency panel", + "actor": { + "id": 10088, + "name": "Grace Hopper" + }, + "created_at": 1791100800 + } + ] + } + } + } + } }, - "timezone": { - "type": "string", - "description": "Timezone in which the rule executes. IANA timezone name; defaults to `Asia/Shanghai`.", - "default": "Asia/Shanghai" + "400": { + "$ref": "#/components/responses/BadRequest" }, - "delay_seconds": { - "type": "integer", - "description": "Query time offset in seconds: each evaluation reads data as of `schedule time − delay_seconds` to tolerate ingestion lag; `0` means no offset." + "401": { + "$ref": "#/components/responses/Unauthorized" }, - "enabled_times": { - "type": "array", - "items": { - "$ref": "#/components/schemas/EnabledTime" - }, - "description": "Effective time windows; each entry has `days` (0–6, 0 = Sunday) and `stime`/`etime` (`HH:MM`), interpreted in the rule's `timezone`; an empty list disables the rule." + "403": { + "$ref": "#/components/responses/Forbidden" }, - "annotations": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom annotation key-value pairs attached to alert events; keys must not start with `$` (reserved for query field references)." + "404": { + "$ref": "#/components/responses/NotFound" }, - "description_type": { - "type": "string", - "enum": [ - "text", - "markdown" - ], - "description": "Format of `description`, `text` or `markdown`; treated as `text` when omitted." + "429": { + "$ref": "#/components/responses/TooManyRequests" }, - "description": { - "type": "string", - "description": "Rule description in the format given by `description_type`, shown with alert events." - }, - "repeat_interval": { - "type": "integer", - "format": "int64", - "description": "Interval in seconds between repeated notifications for a firing alert; values below 1 fall back to the default of 3600." - }, - "repeat_total": { - "type": "integer", - "format": "int64", - "description": "Maximum number of repeated notifications for the same alert; values below 1 fall back to the default of 3." + "500": { + "$ref": "#/components/responses/ServerError" + } + }, + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DashboardIDRequest" + }, + "example": { + "dashboard_id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2101" + } + } } } - }, - "AlertRuleExportListResponse": { - "type": "array", - "description": "List of exported rule configurations, compatible with `POST /monit/rule/import`.", - "items": { - "$ref": "#/components/schemas/AlertRuleExport" - } - }, - "DSClickHouseConfig": { - "type": "object", - "description": "ClickHouse datasource configuration. TLS fields are inherited from TLSClientConfig.", - "properties": { - "database": { - "type": "string", - "description": "Default database for authentication." - }, - "username": { - "type": "string", - "description": "ClickHouse authentication username." - }, - "password": { - "type": "string", - "description": "ClickHouse authentication password." - }, - "open_conns": { - "type": "integer", - "description": "Maximum number of open connections in the pool; `0` or omitted uses the default of 32." - }, - "idle_conns": { - "type": "integer", - "description": "Maximum number of idle connections in the pool; `0` or omitted uses the default of 4." + } + }, + "/monit/dashboard/revisions/get": { + "post": { + "operationId": "monit-dashboard-revision-read-get", + "summary": "Get dashboard revision", + "description": "Fetch one historical revision with its full definition.", + "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- Revision numbers are per dashboard and start at 1.\n- A revision that has aged out of the 20-entry window returns `DashboardNotFound`.", + "href": "/en/api-reference/monitors/dashboards/monit-dashboard-revision-read-get", + "metadata": { + "sidebarTitle": "Get dashboard revision" + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/DashboardRevisionResource" + } + } + } + ] + }, + "example": { + "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", + "data": { + "dashboard_id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2101", + "schema_version": "dashboard.v1", + "revision": 6, + "folder_id": 12, + "definition": { + "title": "Checkout service overview", + "description": "Traffic, errors and dependencies for the checkout service.", + "default_time_range": { + "from": "now-1h", + "to": "now" + }, + "refresh_interval": "1m", + "variables": [ + { + "kind": "custom", + "name": "env", + "label": "Environment", + "selection": { + "mode": "single", + "include_all": false + }, + "options": [ + { + "text": "Production", + "value": "prod" + }, + { + "text": "Staging", + "value": "staging" + } + ], + "default": { + "kind": "values", + "values": [ + "prod" + ] + } + } + ], + "tabs": [ + { + "id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2202", + "title": "Overview", + "description": "Golden signals.", + "top_panels": [], + "sections": [ + { + "id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2303", + "title": "Traffic", + "description": "Request rate and latency.", + "collapsed": false, + "panels": [ + { + "id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2404", + "title": "Request rate", + "grid": { + "x": 0, + "y": 0, + "w": 12, + "h": 8 + }, + "datasource_ref": { + "kind": "fixed", + "datasource_id": 10, + "datasource_type": "prometheus" + }, + "queries": [ + { + "ref_id": "A", + "legend_alias": "{{env}} requests", + "query": { + "mode": "range", + "expr": "sum(rate(http_requests_total{env=\"{{env}}\"}[5m]))", + "args": {}, + "min_step_seconds": 30 + } + } + ], + "viz_config": { + "kind": "time_series", + "options": {}, + "unit": "count_per_second", + "decimals": 2, + "threshold": { + "mode": "higher_is_worse", + "warning": 1000, + "critical": 2000 + } + } + } + ] + } + ] + } + ] + }, + "message": "Initial import", + "actor": { + "id": 10023, + "name": "Ada Lovelace" + }, + "created_at": 1791000000 + } + } + } + } }, - "lifetime_seconds": { - "type": "integer", - "format": "int64", - "description": "Maximum connection lifetime in seconds; `0` or omitted uses the default of 600 (10 minutes)." + "400": { + "$ref": "#/components/responses/BadRequest" }, - "timeout_mills": { - "type": "integer", - "format": "int64", - "description": "Per-query timeout in milliseconds; `0` or omitted uses the default of 10000 (10 seconds)." + "401": { + "$ref": "#/components/responses/Unauthorized" }, - "max_execution_seconds": { - "type": "integer", - "format": "int64", - "description": "Max query execution time in seconds." + "403": { + "$ref": "#/components/responses/Forbidden" }, - "dial_timeout_mills": { - "type": "integer", - "format": "int64", - "description": "Dial timeout in milliseconds." + "404": { + "$ref": "#/components/responses/NotFound" }, - "tls_enabled": { - "type": "boolean", - "description": "Whether TLS is enabled; when `false`, all `tls_*` fields are cleared before saving." + "429": { + "$ref": "#/components/responses/TooManyRequests" }, - "tls_ca": { - "type": "string", - "description": "PEM-encoded CA certificate used to verify the server certificate." + "500": { + "$ref": "#/components/responses/ServerError" + } + }, + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DashboardRevisionGetRequest" + }, + "example": { + "dashboard_id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2101", + "revision": 6 + } + } + } + } + } + }, + "/monit/dashboard/outline": { + "post": { + "operationId": "monit-dashboard-read-outline", + "summary": "Get dashboard outline", + "description": "Get a dashboard's structure without queries or definitions.", + "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- 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.", + "href": "/en/api-reference/monitors/dashboards/monit-dashboard-read-outline", + "metadata": { + "sidebarTitle": "Get dashboard outline" + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/DashboardOutline" + } + } + } + ] + }, + "example": { + "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", + "data": { + "dashboard": { + "dashboard_id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2101", + "title": "Checkout service overview", + "description": "Traffic, errors and dependencies for the checkout service.", + "revision": 7, + "updated_at": 1791100800 + }, + "folder": { + "folder_id": 12, + "breadcrumb": [ + "Production", + "Checkout" + ] + }, + "variables": [ + { + "name": "env", + "label": "Environment", + "kind": "custom", + "selection": { + "mode": "single", + "include_all": false + } + } + ], + "tabs": [ + { + "id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2202", + "title": "Overview", + "description": "Golden signals.", + "breadcrumb": [ + "Checkout service overview", + "Overview" + ], + "top_panels": [], + "sections": [ + { + "id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2303", + "title": "Traffic", + "description": "Request rate and latency.", + "breadcrumb": [ + "Checkout service overview", + "Overview", + "Traffic" + ], + "panels": [ + { + "id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2404", + "title": "Request rate", + "breadcrumb": [ + "Checkout service overview", + "Overview", + "Traffic", + "Request rate" + ], + "viz_config": { + "kind": "time_series" + }, + "datasource_type": "prometheus" + } + ] + } + ] + } + ] + } + } + } + } }, - "tls_cert": { - "type": "string", - "description": "PEM-encoded client certificate for mutual TLS; must be configured together with `tls_key`." + "400": { + "$ref": "#/components/responses/BadRequest" }, - "tls_key": { - "type": "string", - "description": "PEM-encoded client private key; must be configured together with `tls_cert`." + "401": { + "$ref": "#/components/responses/Unauthorized" }, - "tls_skip_verify": { - "type": "boolean", - "description": "Whether to skip server certificate verification (insecure, for self-signed setups only)." + "403": { + "$ref": "#/components/responses/Forbidden" }, - "tls_server_name": { - "type": "string", - "description": "Server name used for TLS SNI and certificate verification; defaults to the host from the connection address when empty." + "404": { + "$ref": "#/components/responses/NotFound" }, - "tls_min_version": { - "type": "string", - "description": "Minimum TLS version, one of `1.0`, `1.1`, `1.2`, `1.3`; empty means no constraint and it must not exceed `tls_max_version`." + "429": { + "$ref": "#/components/responses/TooManyRequests" }, - "tls_max_version": { - "type": "string", - "description": "Maximum TLS version, one of `1.0`, `1.1`, `1.2`, `1.3`; empty means no constraint." + "500": { + "$ref": "#/components/responses/ServerError" + } + }, + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DashboardOutlineRequest" + }, + "example": { + "dashboard_id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2101", + "target_id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2404" + } + } } } - }, - "DSElasticSearchConfig": { - "type": "object", - "description": "Elasticsearch datasource configuration.", - "properties": { - "deployment": { - "type": "string", - "enum": [ - "cloud", - "self-managed" - ], - "description": "Deployment type. `cloud` uses Elastic Cloud; `self-managed` uses a self-hosted cluster." - }, - "timeout_mills": { - "type": "integer", - "format": "int64", - "description": "Per-query timeout in milliseconds; `0` or omitted uses the default of 10000 (10 seconds)." - }, - "cloud_id": { - "type": "string", - "description": "Elastic Cloud deployment ID. Only for `cloud` deployment." - }, - "api_key": { - "type": "string", - "description": "Elastic Cloud API key. Only for `cloud` deployment." + } + }, + "/monit/dashboard/runtime/variables/resolve": { + "post": { + "operationId": "monit-dashboard-variable-read-resolve", + "summary": "Resolve dashboard variables", + "description": "Resolve every variable of a stored dashboard for a time range.", + "tags": [ + "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}$`.", + "href": "/en/api-reference/monitors/dashboards/monit-dashboard-variable-read-resolve", + "metadata": { + "sidebarTitle": "Resolve dashboard variables" + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/DashboardVariablesResolveResponse" + } + } + } + ] + }, + "example": { + "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", + "data": { + "dashboard_id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2101", + "revision": 7, + "variables": [ + { + "name": "env", + "kind": "custom", + "candidates": [ + { + "text": "Production", + "value": "prod" + }, + { + "text": "Staging", + "value": "staging" + } + ], + "selection": { + "kind": "values", + "values": [ + "prod" + ] + } + } + ], + "selections": { + "env": { + "kind": "values", + "values": [ + "prod" + ] + } + } + } + } + } + } }, - "username": { - "type": "string", - "description": "Username for `self-managed` deployment." + "400": { + "$ref": "#/components/responses/BadRequest" }, - "password": { - "type": "string", - "description": "Authentication password for self-managed clusters; ignored when `service_token` is set." + "401": { + "$ref": "#/components/responses/Unauthorized" }, - "service_token": { - "type": "string", - "description": "Service token; overrides username/password if set." + "403": { + "$ref": "#/components/responses/Forbidden" }, - "tls_ca": { - "type": "string", - "description": "PEM-encoded CA certificate used to verify the Elasticsearch server certificate." + "404": { + "$ref": "#/components/responses/NotFound" }, - "certificate_fingerprint": { - "type": "string", - "description": "SHA-256 fingerprint of the Elasticsearch CA certificate, used to verify the server chain (the recommended check for ES 8 default security)." + "429": { + "$ref": "#/components/responses/TooManyRequests" }, - "headers": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Custom HTTP headers added to every request, each entry formatted as `Key: Value`." + "500": { + "$ref": "#/components/responses/ServerError" + } + }, + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DashboardVariablesResolveRequest" + }, + "example": { + "dashboard_id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2101", + "time": { + "from_ms": 1791100800000, + "to_ms": 1791104400000 + }, + "variables": { + "env": { + "kind": "values", + "values": [ + "prod" + ] + } + } + } + } } } - }, - "DSLokiConfig": { - "type": "object", - "description": "Loki datasource configuration. TLS fields are inherited from TLSClientConfig.", - "properties": { - "basic_auth_enabled": { - "type": "boolean", - "description": "Whether HTTP Basic Auth is enabled; when `false`, `basic_auth_username`/`basic_auth_password` are ignored." - }, - "basic_auth_username": { - "type": "string", - "description": "Basic Auth username, effective when `basic_auth_enabled` is `true`." - }, - "basic_auth_password": { - "type": "string", - "description": "Basic Auth password, effective when `basic_auth_enabled` is `true`." - }, - "headers": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Custom HTTP headers added to every request, each entry formatted as `Key: Value`; usable for tenancy headers such as `X-Scope-OrgID`." - }, - "params": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Custom query parameters appended to every request URL, each entry formatted as `key=value`." - }, - "tls_ca": { - "type": "string", - "description": "PEM-encoded CA certificate used to verify the server certificate." + } + }, + "/monit/dashboard/runtime/variables/preview": { + "post": { + "operationId": "monit-dashboard-variable-read-preview", + "summary": "Preview draft variables", + "description": "Resolve a draft variable set that is not stored in any dashboard.", + "tags": [ + "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`.", + "href": "/en/api-reference/monitors/dashboards/monit-dashboard-variable-read-preview", + "metadata": { + "sidebarTitle": "Preview draft variables" + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/DashboardVariablesPreviewResponse" + } + } + } + ] + }, + "example": { + "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", + "data": { + "variables": [ + { + "name": "env", + "kind": "custom", + "candidates": [ + { + "text": "Production", + "value": "prod" + }, + { + "text": "Staging", + "value": "staging" + } + ], + "selection": { + "kind": "values", + "values": [ + "prod" + ] + } + } + ], + "selections": { + "env": { + "kind": "values", + "values": [ + "prod" + ] + } + } + } + } + } + } }, - "tls_cert": { - "type": "string", - "description": "PEM-encoded client certificate for mutual TLS; must be configured together with `tls_key`." + "400": { + "$ref": "#/components/responses/BadRequest" }, - "tls_key": { - "type": "string", - "description": "PEM-encoded client private key; must be configured together with `tls_cert`." + "401": { + "$ref": "#/components/responses/Unauthorized" }, - "tls_skip_verify": { - "type": "boolean", - "description": "Whether to skip server certificate verification (insecure, for self-signed setups only)." + "403": { + "$ref": "#/components/responses/Forbidden" }, - "tls_server_name": { - "type": "string", - "description": "Server name used for TLS SNI and certificate verification; defaults to the host from the connection address when empty." + "404": { + "$ref": "#/components/responses/NotFound" }, - "tls_min_version": { - "type": "string", - "description": "Minimum TLS version, one of `1.0`, `1.1`, `1.2`, `1.3`; empty means no constraint and it must not exceed `tls_max_version`." + "429": { + "$ref": "#/components/responses/TooManyRequests" }, - "tls_max_version": { - "type": "string", - "description": "Maximum TLS version, one of `1.0`, `1.1`, `1.2`, `1.3`; empty means no constraint." + "500": { + "$ref": "#/components/responses/ServerError" + } + }, + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DashboardVariablesPreviewRequest" + }, + "example": { + "context": { + "kind": "new", + "folder_id": 12 + }, + "variables": [ + { + "kind": "custom", + "name": "env", + "label": "Environment", + "selection": { + "mode": "single", + "include_all": false + }, + "options": [ + { + "text": "Production", + "value": "prod" + }, + { + "text": "Staging", + "value": "staging" + } + ], + "default": { + "kind": "values", + "values": [ + "prod" + ] + } + } + ], + "selections": { + "env": { + "kind": "values", + "values": [ + "prod" + ] + } + }, + "time": { + "from_ms": 1791100800000, + "to_ms": 1791104400000 + } + } + } } } - }, - "DSMySQLConfig": { - "type": "object", - "description": "MySQL datasource configuration. TLS fields are inherited from TLSClientConfig.", - "properties": { - "username": { - "type": "string", - "description": "MySQL authentication username." - }, - "password": { - "type": "string", - "description": "MySQL authentication password." - }, - "open_conns": { - "type": "integer", - "description": "Maximum open connections." - }, - "idle_conns": { - "type": "integer", - "description": "Maximum idle connections." - }, - "lifetime_seconds": { - "type": "integer", - "format": "int64", - "description": "Connection maximum lifetime in seconds." - }, - "timeout_mills": { - "type": "integer", - "format": "int64", - "description": "Query timeout in milliseconds." - }, - "tls_mode": { - "type": "string", - "enum": [ - "disable", - "require", - "verify-full" - ], - "description": "TLS mode for the MySQL connection. Empty keeps the legacy per-field TLS behavior. `disable` = no TLS (all `tls_*` fields are cleared on save); `require` = TLS without server certificate verification; `verify-full` = TLS with full server verification (CA chain and hostname). MySQL has no `verify-ca` — verifying the CA implies verifying the hostname." - }, - "tls_ca": { - "type": "string", - "description": "PEM-encoded CA certificate used to verify the server certificate; only allowed when `tls_mode` is `verify-full` (or empty legacy mode)." + } + }, + "/monit/dashboard/runtime/queries/resolve": { + "post": { + "operationId": "monit-dashboard-query-read-resolve", + "summary": "Resolve panel queries", + "description": "Bind panel queries to datasources and substitute variables without executing them.", + "tags": [ + "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\"`.", + "href": "/en/api-reference/monitors/dashboards/monit-dashboard-query-read-resolve", + "metadata": { + "sidebarTitle": "Resolve panel queries" + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/DashboardQueriesResolveResponse" + } + } + } + ] + }, + "example": { + "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", + "data": { + "dashboard_id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2101", + "revision": 7, + "time": { + "from_ms": 1791100800000, + "to_ms": 1791104400000 + }, + "variables": { + "env": { + "kind": "values", + "values": [ + "prod" + ] + } + }, + "panels": [ + { + "panel_id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2404", + "state": "success", + "queries": [ + { + "ref_id": "A", + "datasource": { + "id": 10, + "type": "prometheus", + "name": "Prometheus Prod" + }, + "mode": "range", + "expr": "sum(rate(http_requests_total{env=\"prod\"}[5m]))", + "args": {}, + "min_step_seconds": 30 + } + ] + } + ] + } + } + } + } }, - "tls_cert": { - "type": "string", - "description": "PEM-encoded client certificate for mutual TLS; must be configured together with `tls_key`." + "400": { + "$ref": "#/components/responses/BadRequest" }, - "tls_key": { - "type": "string", - "description": "PEM-encoded client private key; must be configured together with `tls_cert`." + "401": { + "$ref": "#/components/responses/Unauthorized" }, - "tls_skip_verify": { - "type": "boolean", - "description": "Whether to skip server certificate verification; derived from `tls_mode` when set (`require` → `true`, `verify-full` → `false`) — only manually effective under legacy empty `tls_mode`." + "403": { + "$ref": "#/components/responses/Forbidden" }, - "tls_server_name": { - "type": "string", - "description": "Server name used for TLS SNI and certificate verification; defaults to the host from the connection address when empty." + "404": { + "$ref": "#/components/responses/NotFound" }, - "tls_min_version": { - "type": "string", - "description": "Minimum TLS version, one of `1.0`, `1.1`, `1.2`, `1.3`; empty means no constraint and it must not exceed `tls_max_version`." + "429": { + "$ref": "#/components/responses/TooManyRequests" }, - "tls_max_version": { - "type": "string", - "description": "Maximum TLS version, one of `1.0`, `1.1`, `1.2`, `1.3`; empty means no constraint." + "500": { + "$ref": "#/components/responses/ServerError" + } + }, + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DashboardQueriesResolveRequest" + }, + "example": { + "dashboard_id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2101", + "panel_ids": [ + "01990d7a-9c5b-7ab0-9c18-33e38f6f2404" + ], + "time": { + "from_ms": 1791100800000, + "to_ms": 1791104400000 + }, + "variables": { + "env": { + "kind": "values", + "values": [ + "prod" + ] + } + } + } + } } } - }, - "DSOracleConfig": { - "type": "object", - "description": "Oracle datasource configuration.", - "properties": { - "username": { - "type": "string", - "description": "Oracle authentication username." + } + }, + "/monit/dashboard/panel/run": { + "post": { + "operationId": "monit-dashboard-panel-read-run", + "summary": "Run dashboard panel", + "description": "Execute one panel of a stored dashboard and return the datasource results.", + "tags": [ + "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.", + "href": "/en/api-reference/monitors/dashboards/monit-dashboard-panel-read-run", + "metadata": { + "sidebarTitle": "Run dashboard panel" + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/DashboardPanelRunResponse" + } + } + } + ] + }, + "example": { + "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", + "data": { + "dashboard_id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2101", + "panel_id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2404", + "revision": 7, + "run_state": "success", + "time": { + "from_ms": 1791100800000, + "to_ms": 1791104400000 + }, + "variables": { + "env": { + "kind": "values", + "values": [ + "prod" + ] + } + }, + "refs": [ + { + "ref_id": "A", + "state": "success", + "child_request_id": "01HK8XQH7B4N0PQR2S6TVW9X3M", + "execution": { + "status": "success", + "frames": [ + { + "schema": { + "fields": [ + { + "name": "time", + "type": "time" + }, + { + "name": "value", + "type": "number" + } + ] + }, + "data": { + "values": [ + [ + 1791100800000, + 812.4 + ], + [ + 1791100860000, + 846.1 + ] + ] + } + } + ] + } + } + ], + "display": { + "kind": "time_series", + "options": {}, + "unit": "count_per_second", + "decimals": 2, + "threshold": { + "mode": "higher_is_worse", + "warning": 1000, + "critical": 2000 + } + }, + "budget": { + "max_concurrency": 6, + "execution_count": 1 + } + } + } + } + } }, - "password": { - "type": "string", - "description": "Oracle authentication password." + "400": { + "$ref": "#/components/responses/BadRequest" }, - "options": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Extra connection options as key-value pairs." + "401": { + "$ref": "#/components/responses/Unauthorized" }, - "open_conns": { - "type": "integer", - "description": "Maximum number of open connections in the pool; `0` or omitted uses the default of 32." + "403": { + "$ref": "#/components/responses/Forbidden" }, - "idle_conns": { - "type": "integer", - "description": "Maximum number of idle connections in the pool; `0` or omitted uses the default of 4." + "404": { + "$ref": "#/components/responses/NotFound" }, - "lifetime_seconds": { - "type": "integer", - "format": "int64", - "description": "Maximum connection lifetime in seconds; `0` or omitted uses the default of 600 (10 minutes)." + "429": { + "$ref": "#/components/responses/TooManyRequests" }, - "timeout_mills": { - "type": "integer", - "format": "int64", - "description": "Per-query timeout in milliseconds; `0` or omitted uses the default of 10000 (10 seconds)." + "500": { + "$ref": "#/components/responses/ServerError" + } + }, + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DashboardPanelRunRequest" + }, + "example": { + "dashboard_id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2101", + "panel_id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2404", + "revision": 7, + "time": { + "from_ms": 1791100800000, + "to_ms": 1791104400000 + }, + "variables": { + "env": { + "kind": "values", + "values": [ + "prod" + ] + } + }, + "max_data_points": 100 + } + } } } - }, - "DSPayload": { - "type": "object", - "description": "Type-specific datasource configuration. Include only the block matching `type_ident`.", - "properties": { - "prometheus": { - "$ref": "#/components/schemas/DSPrometheusConfig" - }, - "loki": { - "$ref": "#/components/schemas/DSLokiConfig" - }, - "mysql": { - "$ref": "#/components/schemas/DSMySQLConfig" - }, - "oracle": { - "$ref": "#/components/schemas/DSOracleConfig" - }, - "postgres": { - "$ref": "#/components/schemas/DSPostgresConfig" - }, - "clickhouse": { - "$ref": "#/components/schemas/DSClickHouseConfig" - }, - "elasticsearch": { - "$ref": "#/components/schemas/DSElasticSearchConfig" - }, - "sls": { - "$ref": "#/components/schemas/DSSLSConfig" - }, - "victorialogs": { - "$ref": "#/components/schemas/DSVictoriaLogsConfig" - }, - "tencent_cls": { - "$ref": "#/components/schemas/DSTencentCLSConfig", - "description": "Tencent CLS credentials. Required when `type_ident` is `tencent_cls`." - }, - "kafka": { - "$ref": "#/components/schemas/DSKafkaConfig", - "x-flashduty-preserve-absence": true - }, - "mongodb_mongod": { - "$ref": "#/components/schemas/DSMongoDBConfig", - "x-flashduty-preserve-absence": true - }, - "mongodb_mongos": { - "$ref": "#/components/schemas/DSMongoDBConfig", - "x-flashduty-preserve-absence": true - }, - "redis_node": { - "$ref": "#/components/schemas/DSRedisNodeConfig", - "x-flashduty-preserve-absence": true - }, - "redis_sentinel": { - "$ref": "#/components/schemas/DSRedisSentinelConfig", - "x-flashduty-preserve-absence": true + } + }, + "/monit/dashboard/panel/preview": { + "post": { + "operationId": "monit-dashboard-panel-read-preview", + "summary": "Preview draft panel", + "description": "Execute a draft panel inline without saving a dashboard revision.", + "tags": [ + "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`.", + "href": "/en/api-reference/monitors/dashboards/monit-dashboard-panel-read-preview", + "metadata": { + "sidebarTitle": "Preview draft panel" } - } - }, - "DSPostgresConfig": { - "type": "object", - "description": "PostgreSQL datasource configuration.", - "properties": { - "username": { - "type": "string", - "description": "PostgreSQL authentication username." - }, - "password": { - "type": "string", - "description": "PostgreSQL authentication password." - }, - "open_conns": { - "type": "integer", - "description": "Maximum number of open connections in the pool; `0` or omitted uses the default of 32." - }, - "idle_conns": { - "type": "integer", - "description": "Maximum number of idle connections in the pool; `0` or omitted uses the default of 4." + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/DashboardPanelPreviewResponse" + } + } + } + ] + }, + "example": { + "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", + "data": { + "panel_id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2404", + "run_state": "success", + "time": { + "from_ms": 1791100800000, + "to_ms": 1791104400000 + }, + "variables": { + "env": { + "kind": "values", + "values": [ + "prod" + ] + } + }, + "refs": [ + { + "ref_id": "A", + "state": "success", + "child_request_id": "01HK8XQH7B4N0PQR2S6TVW9X3M", + "execution": { + "status": "success", + "frames": [ + { + "schema": { + "fields": [ + { + "name": "time", + "type": "time" + }, + { + "name": "value", + "type": "number" + } + ] + }, + "data": { + "values": [ + [ + 1791100800000, + 812.4 + ], + [ + 1791100860000, + 846.1 + ] + ] + } + } + ] + } + } + ], + "display": { + "kind": "time_series", + "options": {}, + "unit": "count_per_second", + "decimals": 2, + "threshold": { + "mode": "higher_is_worse", + "warning": 1000, + "critical": 2000 + } + }, + "budget": { + "max_concurrency": 6, + "execution_count": 1 + } + } + } + } + } }, - "lifetime_seconds": { - "type": "integer", - "format": "int64", - "description": "Maximum connection lifetime in seconds; `0` or omitted uses the default of 600 (10 minutes)." + "400": { + "$ref": "#/components/responses/BadRequest" }, - "timeout_mills": { - "type": "integer", - "format": "int64", - "description": "Per-query timeout in milliseconds; `0` or omitted uses the default of 10000 (10 seconds)." + "401": { + "$ref": "#/components/responses/Unauthorized" }, - "ssl_mode": { - "type": "string", - "enum": [ - "disable", - "require", - "verify-ca", - "verify-full" - ], - "description": "SSL mode for the PostgreSQL connection. Empty keeps the legacy behavior inferred from `tls_ca`. `disable` = no TLS (all `tls_*` fields are cleared on save); `require` = TLS without server certificate verification (`tls_ca` not allowed); `verify-ca` = verify the server certificate CA chain but not the hostname; `verify-full` = verify both CA chain and hostname." + "403": { + "$ref": "#/components/responses/Forbidden" }, - "tls_ca": { - "type": "string", - "description": "PEM-encoded CA certificate used to verify the server certificate; used with `ssl_mode` `verify-ca`/`verify-full` and rejected under `require`." + "404": { + "$ref": "#/components/responses/NotFound" }, - "tls_cert": { - "type": "string", - "description": "PEM-encoded client certificate for mutual TLS; must be configured together with `tls_key`." + "429": { + "$ref": "#/components/responses/TooManyRequests" }, - "tls_key": { - "type": "string", - "description": "PEM-encoded client private key; must be configured together with `tls_cert`." + "500": { + "$ref": "#/components/responses/ServerError" + } + }, + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DashboardPanelPreviewRequest" + }, + "example": { + "context": { + "kind": "existing", + "dashboard_id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2101" + }, + "panel": { + "id": "01990d7a-9c5b-7ab0-9c18-33e38f6f2404", + "title": "Request rate", + "grid": { + "x": 0, + "y": 0, + "w": 12, + "h": 8 + }, + "datasource_ref": { + "kind": "fixed", + "datasource_id": 10, + "datasource_type": "prometheus" + }, + "queries": [ + { + "ref_id": "A", + "legend_alias": "{{env}} requests", + "query": { + "mode": "range", + "expr": "sum(rate(http_requests_total{env=\"{{env}}\"}[5m]))", + "args": {}, + "min_step_seconds": 30 + } + } + ], + "viz_config": { + "kind": "time_series", + "options": {}, + "unit": "count_per_second", + "decimals": 2, + "threshold": { + "mode": "higher_is_worse", + "warning": 1000, + "critical": 2000 + } + } + }, + "variables": [ + { + "kind": "custom", + "name": "env", + "label": "Environment", + "selection": { + "mode": "single", + "include_all": false + }, + "options": [ + { + "text": "Production", + "value": "prod" + }, + { + "text": "Staging", + "value": "staging" + } + ], + "default": { + "kind": "values", + "values": [ + "prod" + ] + } + } + ], + "selections": { + "env": { + "kind": "values", + "values": [ + "prod" + ] + } + }, + "time": { + "from_ms": 1791100800000, + "to_ms": 1791104400000 + }, + "max_data_points": 100 + } + } } } - }, - "DSPrometheusConfig": { - "type": "object", - "description": "Prometheus datasource configuration. TLS fields are inherited from TLSClientConfig.", - "properties": { - "basic_auth_enabled": { - "type": "boolean", - "description": "Enable HTTP Basic Auth." + } + }, + "/monit/folder/list": { + "post": { + "operationId": "monit-folder-read-list", + "summary": "List monitor folders", + "description": "List every monitor folder the caller can read.", + "tags": [ + "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.\n- Folder writes (`create`, `update`, `move`, `delete`) are still JWT-only and are not part of the public API.", + "href": "/en/api-reference/monitors/rule-folders/monit-folder-read-list", + "metadata": { + "sidebarTitle": "List monitor folders" + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FolderItem" + } + } + } + } + ] + }, + "example": { + "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", + "data": [ + { + "id": 12, + "account_id": 10023, + "parent_id": 10, + "parent_path": "10", + "team_id": 0, + "name": "Checkout", + "note": "Checkout service folders", + "creator_id": 10023, + "creator_name": "Ada Lovelace", + "updater_id": 10088, + "updater_name": "Grace Hopper", + "created_at": 1791000000, + "updated_at": 1791100800 + } + ] + } + } + } }, - "basic_auth_username": { - "type": "string", - "description": "Basic auth username." + "400": { + "$ref": "#/components/responses/BadRequest" }, - "basic_auth_password": { - "type": "string", - "description": "Basic auth password." + "401": { + "$ref": "#/components/responses/Unauthorized" }, - "headers": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Custom HTTP headers in `Key: Value` format." + "429": { + "$ref": "#/components/responses/TooManyRequests" }, - "params": { - "type": "array", - "items": { - "type": "string" + "500": { + "$ref": "#/components/responses/ServerError" + } + } + } + } + }, + "components": { + "securitySchemes": { + "AppKeyAuth": { + "type": "apiKey", + "in": "query", + "name": "app_key", + "description": "App key issued from the Flashduty console under Account → APP Keys. Required on every public API call. Keep it secret — it grants the same access as the owning account." + } + }, + "responses": { + "BadRequest": { + "description": "Invalid request — usually a missing or malformed parameter.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" }, - "description": "Custom query parameters in `key=value` format." - }, - "tls_ca": { - "type": "string", - "description": "PEM-encoded CA certificate used to verify the server certificate." - }, - "tls_cert": { - "type": "string", - "description": "PEM-encoded client certificate for mutual TLS; must be configured together with `tls_key`." - }, - "tls_key": { - "type": "string", - "description": "PEM-encoded client private key; must be configured together with `tls_cert`." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Whether to skip server certificate verification (insecure, for self-signed setups only)." - }, - "tls_server_name": { - "type": "string", - "description": "Server name used for TLS SNI and certificate verification; defaults to the host from the connection address when empty." - }, - "tls_min_version": { - "type": "string", - "description": "Minimum TLS version, one of `1.0`, `1.1`, `1.2`, `1.3`; empty means no constraint and it must not exceed `tls_max_version`." - }, - "tls_max_version": { - "type": "string", - "description": "Maximum TLS version, one of `1.0`, `1.1`, `1.2`, `1.3`; empty means no constraint." + "examples": { + "missingParameter": { + "value": { + "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", + "error": { + "code": "InvalidParameter", + "message": "The specified parameter is not valid." + } + } + } + } } } }, - "DSSLSConfig": { - "type": "object", - "description": "Alibaba Cloud SLS datasource configuration.", - "properties": { - "access_key_id": { - "type": "string", - "description": "Alibaba Cloud Access Key ID." - }, - "access_key_secret": { - "type": "string", - "description": "Alibaba Cloud Access Key Secret." - }, - "headers": { - "type": "array", - "items": { - "type": "string" + "Unauthorized": { + "description": "Missing or invalid app_key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" }, - "description": "Custom HTTP headers." + "examples": { + "missingAppKey": { + "value": { + "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", + "error": { + "code": "Unauthorized", + "message": "You are unauthorized." + } + } + } + } } } }, - "DSVictoriaLogsConfig": { + "Forbidden": { + "description": "The app_key is valid but lacks permission for this operation.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + }, + "examples": { + "noEditPermission": { + "value": { + "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", + "error": { + "code": "AccessDenied", + "message": "Access Denied." + } + } + } + } + } + } + }, + "NotFound": { + "description": "The referenced resource does not exist or has been deleted. Note: Flashduty historically returns HTTP 400 with code `ResourceNotFound` for missing domain entities; a true 404 is reserved for unknown routes.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + }, + "examples": { + "resourceMissing": { + "value": { + "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", + "error": { + "code": "ResourceNotFound", + "message": "The resource you request is not found" + } + } + } + } + } + } + }, + "TooManyRequests": { + "description": "Rate limit hit. Either the global API limit, a per-account limit, or a per-integration limit.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + }, + "examples": { + "rateLimited": { + "value": { + "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", + "error": { + "code": "RequestTooFrequently", + "message": "Request too frequently." + } + } + } + } + } + } + }, + "ServerError": { + "description": "Unexpected server-side error. Include the request_id when reporting.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + }, + "examples": { + "internal": { + "value": { + "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", + "error": { + "code": "InternalError", + "message": "We encountered an internal error, and it has been reported. Please try again later." + } + } + } + } + } + } + }, + "ServiceUnavailable": { + "description": "The service is temporarily unavailable. Include the request_id when reporting.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + }, + "examples": { + "serviceUnavailable": { + "value": { + "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", + "error": { + "code": "ServiceUnavailable", + "message": "service temporarily unavailable" + } + } + } + } + } + } + } + }, + "schemas": { + "AlertRule": { "type": "object", - "description": "VictoriaLogs datasource configuration. TLS fields are inherited from TLSClientConfig.", + "description": "Full alert rule configuration.", "properties": { - "basic_auth_enabled": { - "type": "boolean", - "description": "Whether HTTP Basic Auth is enabled; when `false`, `basic_auth_username`/`basic_auth_password` are ignored." + "id": { + "type": "integer", + "format": "uint64", + "description": "Rule ID. Required for update; omit for create (assigned by the server)." }, - "basic_auth_username": { + "account_id": { + "type": "integer", + "format": "uint64", + "description": "Account ID. Filled by the server from the authenticated identity; do not provide." + }, + "folder_id": { + "type": "integer", + "format": "uint64", + "description": "ID of the folder the rule belongs to. Obtainable via `POST /monit/folder/list`." + }, + "name": { "type": "string", - "description": "Basic Auth username, effective when `basic_auth_enabled` is `true`." + "description": "Rule name. Must be unique within the same folder." }, - "basic_auth_password": { + "labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom labels." + }, + "ds_type": { "type": "string", - "description": "Basic Auth password, effective when `basic_auth_enabled` is `true`." + "description": "Datasource type identifier (e.g. `prometheus`, `elasticsearch`)." }, - "headers": { + "ds_list": { "type": "array", "items": { "type": "string" }, - "description": "Custom HTTP headers added to every request, each entry formatted as `Key: Value`; usable for tenancy headers such as `AccountID`/`ProjectID`." + "description": "Data source name patterns (supports wildcards). At least one of `ds_list` / `ds_ids` must be non-empty; the two are merged to decide which datasources the rule monitors." }, - "params": { + "ds_ids": { "type": "array", "items": { - "type": "string" + "type": "integer", + "format": "uint64" }, - "description": "Custom query parameters appended to every request URL, each entry formatted as `key=value`." - }, - "tls_ca": { - "type": "string", - "description": "PEM-encoded CA certificate used to verify the server certificate." - }, - "tls_cert": { - "type": "string", - "description": "PEM-encoded client certificate for mutual TLS; must be configured together with `tls_key`." + "description": "Datasource IDs, merged with `ds_list` to decide which datasources the rule monitors; IDs survive datasource renames. At least one of `ds_list` and `ds_ids` must be provided." }, - "tls_key": { - "type": "string", - "description": "PEM-encoded client private key; must be configured together with `tls_cert`." + "enabled": { + "type": "boolean", + "description": "Whether the rule is enabled. Updating to `false` makes the server clean up the rule's active alerts." }, - "tls_skip_verify": { + "debug_log_enabled": { "type": "boolean", - "description": "Whether to skip server certificate verification (insecure, for self-signed setups only)." + "description": "Whether to enable debug logging; the edge emits detailed evaluation logs, useful for troubleshooting rules that do not trigger as expected." }, - "tls_server_name": { - "type": "string", - "description": "Server name used for TLS SNI and certificate verification; defaults to the host from the connection address when empty." + "rule_configs": { + "$ref": "#/components/schemas/RuleConfigs", + "description": "Check configuration: query list plus trigger/recovery conditions. Structure see `RuleConfigs`." }, - "tls_min_version": { + "cron_pattern": { "type": "string", - "description": "Minimum TLS version, one of `1.0`, `1.1`, `1.2`, `1.3`; empty means no constraint and it must not exceed `tls_max_version`." + "description": "Schedule expression: a 6-field cron (with seconds) or an `@every 30s` interval descriptor. Must not start with `CRON_TZ=` or `TZ=`; use the `timezone` field instead." }, - "tls_max_version": { + "timezone": { "type": "string", - "description": "Maximum TLS version, one of `1.0`, `1.1`, `1.2`, `1.3`; empty means no constraint." - } - } + "description": "Timezone in which the rule executes. Determines how the cron schedule and effective time windows are interpreted. Only IANA timezone names are accepted (e.g. `Asia/Shanghai`, `UTC`, `Europe/London`); shortcuts and offsets such as `Local`, `UTC+8`, or `CST` are rejected. Treated as `Asia/Shanghai` if empty.", + "default": "Asia/Shanghai" + }, + "delay_seconds": { + "type": "integer", + "description": "Seconds to shift the evaluation query window backward, compensating for data ingestion latency." + }, + "enabled_times": { + "type": "array", + "description": "Time windows when the rule is active. Defaults to all days from 00:00 to 23:59 when omitted or empty.", + "default": [ + { + "days": [ + 1, + 2, + 3, + 4, + 5, + 6, + 0 + ], + "stime": "00:00", + "etime": "23:59" + } + ], + "items": { + "type": "object", + "properties": { + "days": { + "type": "array", + "items": { + "type": "integer" + }, + "description": "Days of week (0=Sunday)." + }, + "stime": { + "type": "string", + "description": "Start time, e.g. `09:00`." + }, + "etime": { + "type": "string", + "description": "End time, e.g. `18:00`." + } + } + } + }, + "annotations": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Annotation key-value pairs delivered with alert events; keys must not start with `$` (reserved for query fields)." + }, + "description_type": { + "type": "string", + "enum": [ + "text", + "markdown" + ], + "default": "text", + "description": "Format for the description. Defaults to `text` when omitted or empty. `text` = plain text; `markdown` = Markdown, rendered as Markdown in alert details." + }, + "description": { + "type": "string", + "description": "Rule description, in Markdown." + }, + "channel_ids": { + "type": "array", + "items": { + "type": "integer", + "format": "uint64" + }, + "description": "Channel IDs to send alerts to." + }, + "repeat_interval": { + "type": "integer", + "format": "int64", + "description": "Notification repeat interval in seconds." + }, + "repeat_total": { + "type": "integer", + "format": "int64", + "description": "Max number of repeat notifications." + }, + "creator_id": { + "type": "integer", + "format": "uint64", + "description": "Creator user ID. Filled by the server from the current user; do not provide." + }, + "creator_name": { + "type": "string", + "description": "Creator name. Filled by the server; do not provide." + }, + "updater_id": { + "type": "integer", + "format": "uint64", + "description": "Last updater user ID. Filled by the server; do not provide." + }, + "updater_name": { + "type": "string", + "description": "Last updater name. Filled by the server; do not provide." + }, + "created_at": { + "type": "integer", + "format": "int64", + "description": "Creation time as a Unix timestamp in seconds. Generated by the server; do not provide." + }, + "updated_at": { + "type": "integer", + "format": "int64", + "description": "Last update time as a Unix timestamp in seconds. Generated by the server; do not provide." + } + }, + "required": [ + "folder_id", + "name", + "ds_type", + "cron_pattern", + "rule_configs" + ] }, - "DataSourceItem": { + "AlertRuleAudit": { "type": "object", - "description": "A monitoring datasource.", + "description": "An audit record capturing a rule snapshot at a point in time.", "required": [ "id", "account_id", - "type_ident", - "name", - "enabled", - "note", - "address", - "edge_cluster_name", - "updated_at", - "payload", - "alerting_enabled" + "alert_rule_id", + "action", + "creator_id", + "creator_name", + "created_at" ], "properties": { "id": { "type": "integer", "format": "uint64", - "description": "Unique datasource ID." + "description": "Audit record ID." }, "account_id": { "type": "integer", "format": "uint64", - "description": "Account ID." - }, - "type_ident": { - "type": "string", - "description": "Datasource type identifier. Allowed: `prometheus`, `loki`, `mysql`, `oracle`, `postgres`, `clickhouse`, `elasticsearch`, `sls`, `tencent_cls`, `victorialogs`, `redis_node`, `redis_sentinel`, `mongodb_mongod`, `mongodb_mongos`, `kafka`。" - }, - "name": { - "type": "string", - "description": "Datasource display name." + "description": "ID of the account that owns the rule." }, - "enabled": { - "type": "boolean", - "description": "Whether business execution is enabled. Disabled datasources reject business queries and tools; enabling does not change alerting_enabled." + "alert_rule_id": { + "type": "integer", + "format": "uint64", + "description": "ID of the alert rule this record belongs to." }, - "note": { + "action": { "type": "string", - "description": "Optional description." + "description": "Action performed: `create` = rule created; `update` = rule updated (covers full updates, field-batch updates, imports and moves).", + "enum": [ + "create", + "update" + ] }, - "address": { + "content": { "type": "string", - "description": "Connection address. For Prometheus/Loki/VictoriaLogs: HTTP URL. For MySQL/Oracle/Postgres/ClickHouse: `host:port`. For SLS: endpoint without http/https prefix. Redis/MongoDB diagnostic types: one host:port, bracket IPv6; no URI, userinfo or query. Kafka: 1–32 unique comma-separated host:port bootstrap addresses; payload has no broker list. At most 4096 characters after normalization.", - "maxLength": 4096 + "description": "JSON string of the full rule snapshot at audit time. Populated on `/monit/rule/audit/detail`, omitted on list responses." }, - "payload": { - "anyOf": [ - { - "$ref": "#/components/schemas/DSPayload" - }, - { - "type": "null" - } - ], - "description": "Type-specific configuration block; must contain the key matching `type_ident`. Always `null` in `/monit/datasource/list` responses (the list query does not read the payload column); populated in create/update/info responses. For `tencent_cls`, `secret_key` is masked to an empty string unless it is an `${env:...}` reference. For diagnostic types, password and Kafka tls_key are omitted from responses unless they are ${env:...} references. On update, omit those fields to preserve stored secrets; explicitly send an empty string to clear. Other configuration fields retain their existing behavior." + "creator_id": { + "type": "integer", + "format": "uint64", + "description": "ID of the user who made this change (taken from the rule's `updater_id` at change time)." }, - "edge_cluster_name": { + "creator_name": { "type": "string", - "description": "Monitors edge cluster name responsible for evaluating rules using this datasource." + "description": "Name of the user who made this change (taken from the rule's `updater_name` at change time)." }, - "updated_at": { + "created_at": { "type": "integer", "format": "int64", - "description": "Last update timestamp, Unix epoch seconds." - }, - "alerting_enabled": { - "description": "Whether alert evaluation is allowed. Alerting also requires enabled=true and an alerting-capable type. Always false for diagnostic-only types; false does not block non-alerting queries or tools.", - "type": "boolean" - } - } - }, - "DataSourceListRequest": { - "type": "object", - "description": "Filter parameters for listing datasources.", - "properties": { - "type": { - "type": "string", - "description": "Datasource type identifier. Omit to return all types. Allowed: `prometheus`, `loki`, `mysql`, `oracle`, `postgres`, `clickhouse`, `elasticsearch`, `sls`, `tencent_cls`, `victorialogs`, `redis_node`, `redis_sentinel`, `mongodb_mongod`, `mongodb_mongos`, `kafka`。" + "description": "When this audit record was produced, as a Unix timestamp in seconds; equals the rule's `updated_at` at change time." } } }, - "DataSourceListResponse": { - "type": "array", - "description": "List of datasources. The `payload` column is not read by this endpoint, so `payload` is `null` in every item.", - "items": { - "$ref": "#/components/schemas/DataSourceItem" - } - }, - "DataSourceUpsertRequest": { + "AlertRuleBasic": { "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": "Basic alert rule information for list views.", "required": [ - "type_ident", + "id", + "account_id", + "folder_id", "name", - "edge_cluster_name", - "payload" + "ds_type", + "enabled", + "debug_log_enabled", + "cron_pattern", + "delay_seconds", + "creator_id", + "creator_name", + "updater_id", + "updater_name", + "created_at", + "updated_at", + "triggered", + "labels", + "timezone", + "active_alert_count" ], "properties": { "id": { "type": "integer", "format": "uint64", - "description": "Datasource ID. Required for update; omit for create." + "description": "Unique rule ID." }, - "type_ident": { - "type": "string", - "description": "Datasource type identifier. Allowed: `prometheus`, `loki`, `mysql`, `oracle`, `postgres`, `clickhouse`, `elasticsearch`, `sls`, `tencent_cls`, `victorialogs`, `redis_node`, `redis_sentinel`, `mongodb_mongod`, `mongodb_mongos`, `kafka`。" + "account_id": { + "type": "integer", + "format": "uint64", + "description": "Account ID." + }, + "folder_id": { + "type": "integer", + "format": "uint64", + "description": "Folder ID." }, "name": { "type": "string", - "description": "Datasource display name. This is the name referenced as `ds_name` in query APIs." + "description": "Rule name." }, - "note": { - "type": "string", - "description": "Optional description." - }, - "address": { - "type": "string", - "description": "Connection address. Required for every type except `elasticsearch` with `deployment: cloud`. Prometheus/Loki/VictoriaLogs: HTTP URL; MySQL/Oracle/Postgres/ClickHouse: `host:port`; SLS: endpoint without the `http(s)://` prefix; `tencent_cls`: must be `cls.tencentcloudapi.com` or `cls.internal.tencentcloudapi.com` (requires Monitors edge >= v0.66.0). Redis/MongoDB diagnostic types: one host:port, bracket IPv6; no URI, userinfo or query. Kafka: 1–32 unique comma-separated host:port bootstrap addresses; payload has no broker list. At most 4096 characters after normalization.", - "maxLength": 4096 - }, - "payload": { - "$ref": "#/components/schemas/DSPayload", - "description": "Type-specific configuration block. Must include the key matching `type_ident`. For diagnostic types, password and Kafka tls_key are omitted from responses unless they are ${env:...} references. On update, omit those fields to preserve stored secrets; explicitly send an empty string to clear. Other configuration fields retain their existing behavior." + "labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom labels." }, - "edge_cluster_name": { + "ds_type": { "type": "string", - "description": "Monitors edge cluster name responsible for evaluating rules using this datasource." + "description": "Data source type, e.g. `prometheus`." }, "enabled": { "type": "boolean", - "description": "Whether business execution is enabled. Omitted on create: true; omitted on update: preserve the current value. Explicit false disables execution; null is invalid. Does not change alerting_enabled.", - "x-flashduty-preserve-absence": true + "description": "Whether the rule is enabled." }, - "alerting_enabled": { - "description": "Whether this datasource may evaluate alerts. Omitted on create: true for alerting types, false for diagnostic-only types; omitted on update: preserve current value. null is invalid. redis_node, redis_sentinel, mongodb_mongod, mongodb_mongos and kafka reject true. Disabling is rejected with conflict when enabled rules reference the datasource.", + "debug_log_enabled": { "type": "boolean", - "x-flashduty-preserve-absence": true - } - } - }, - "DutyError": { - "type": "object", - "description": "Error payload inside the response envelope. Present only on non-2xx responses.", - "properties": { - "code": { - "$ref": "#/components/schemas/ErrorCode" + "description": "Whether debug logging is enabled." }, - "message": { + "cron_pattern": { "type": "string", - "description": "Human-readable error message, localized by the caller's Accept-Language. May contain field names, IDs, or other context from the failing request.", - "example": "The specified parameter template_id is not valid." + "description": "Schedule expression: a 6-field cron with seconds, e.g. `0 * * * * *`, or an `@every 30s` interval descriptor. Must not start with `CRON_TZ=` or `TZ=`; use the `timezone` field instead." }, - "reason": { - "description": "Optional machine-readable rejection reason, including datasource tool failures. Inspect alongside HTTP status and code.", + "timezone": { "type": "string", - "x-flashduty-preserve-absence": true - } - }, - "required": [ - "code", - "message" - ] - }, - "EmptyResponse": { - "type": "object", - "description": "Empty response body. The server returns `data: null` on success.", - "properties": {} - }, - "EnabledTime": { - "type": "object", - "description": "Time window in which the rule is active.", - "properties": { - "days": { - "type": "array", - "items": { - "type": "integer" - }, - "description": "Days of week, 0 = Sunday." + "description": "Timezone in which the rule executes. Determines how the cron schedule and effective time windows are interpreted. Only IANA timezone names are accepted (e.g. `Asia/Shanghai`, `UTC`, `Europe/London`); shortcuts and offsets such as `Local`, `UTC+8`, or `CST` are rejected. Treated as `Asia/Shanghai` if empty.", + "default": "Asia/Shanghai" }, - "stime": { - "type": "string", - "description": "Start time, e.g. `09:00`." + "delay_seconds": { + "type": "integer", + "description": "Evaluation delay in seconds." }, - "etime": { + "creator_id": { + "type": "integer", + "format": "uint64", + "description": "ID of the user who created the rule." + }, + "creator_name": { "type": "string", - "description": "End time, e.g. `18:00`." - } - } - }, - "ErrorCode": { - "type": "string", - "description": "Flashduty error code enum. Every failed API response sets `error.code` to one of these stable wire strings. HTTP status is informational — the authoritative signal is the enum value.\n\n| Code | HTTP | Meaning |\n|---|---|---|\n| `OK` | 200 | Reserved — not returned on real errors. |\n| `InvalidParameter` | 400 | A required parameter is missing or failed validation. |\n| `BadRequest` | 400 | Generic 400 used when no more specific code fits. |\n| `InvalidContentType` | 400 | The `Content-Type` header is not `application/json`. |\n| `ResourceNotFound` | 400 | The referenced resource does not exist. Note: returned as HTTP 400, not 404 (historical choice). |\n| `NoLicense` | 400 | The feature is license-gated and no active license was found. |\n| `ReferenceExist` | 400 | Deletion blocked — other entities still reference this resource. |\n| `Unauthorized` | 401 | `app_key` is missing, invalid, or expired. |\n| `BalanceNotEnough` | 402 | Billing-gated operation with insufficient account balance. |\n| `AccessDenied` | 403 | Authenticated but lacking the permission required for this operation. |\n| `RouteNotFound` | 404 | The request URL path is not a known route. |\n| `MethodNotAllowed` | 405 | The HTTP method is not allowed on this otherwise-known path. |\n| `UndonedOrderExist` | 409 | An outstanding billing order blocks this new one. Wait and retry. |\n| `RequestLocked` | 423 | Operation temporarily locked due to repeated failures. |\n| `EntityTooLarge` | 413 | Request body exceeds the configured max size. |\n| `RequestTooFrequently` | 429 | Rate limit hit — API-global, per-account, or per-integration. |\n| `RequestVerifyRequired` | 428 | Second-factor verification required but not supplied. |\n| `DangerousOperation` | 428 | High-risk operation requires MFA verification. |\n| `InternalError` | 500 | Unhandled server-side error. Include `request_id` in the bug report. |\n| `ServiceUnavailable` | 503 | A backend dependency is unavailable. Try again later. |", - "enum": [ - "OK", - "InvalidParameter", - "BadRequest", - "InvalidContentType", - "ResourceNotFound", - "NoLicense", - "ReferenceExist", - "Unauthorized", - "BalanceNotEnough", - "AccessDenied", - "RouteNotFound", - "MethodNotAllowed", - "UndonedOrderExist", - "RequestLocked", - "EntityTooLarge", - "RequestTooFrequently", - "RequestVerifyRequired", - "DangerousOperation", - "InternalError", - "ServiceUnavailable" - ], - "x-enumDescriptions": { - "OK": "Reserved — not returned on real errors.", - "InvalidParameter": "A required parameter is missing or failed validation.", - "BadRequest": "Generic 400 used when no more specific code fits.", - "InvalidContentType": "The `Content-Type` header is not `application/json`.", - "ResourceNotFound": "The referenced resource does not exist. Note: returned as HTTP 400, not 404 (historical choice).", - "NoLicense": "The feature is license-gated and no active license was found.", - "ReferenceExist": "Deletion blocked — other entities still reference this resource.", - "Unauthorized": "`app_key` is missing, invalid, or expired.", - "BalanceNotEnough": "Billing-gated operation with insufficient account balance.", - "AccessDenied": "Authenticated but lacking the permission required for this operation.", - "RouteNotFound": "The request URL path is not a known route.", - "MethodNotAllowed": "The HTTP method is not allowed on this otherwise-known path.", - "UndonedOrderExist": "An outstanding billing order blocks this new one. Wait and retry.", - "RequestLocked": "Operation temporarily locked due to repeated failures.", - "EntityTooLarge": "Request body exceeds the configured max size.", - "RequestTooFrequently": "Rate limit hit — API-global, per-account, or per-integration.", - "RequestVerifyRequired": "Second-factor verification required but not supplied.", - "DangerousOperation": "High-risk operation requires MFA verification.", - "InternalError": "Unhandled server-side error. Include `request_id` in the bug report.", - "ServiceUnavailable": "A backend dependency is unavailable. Try again later." - }, - "example": "InvalidParameter" - }, - "ErrorResponse": { - "type": "object", - "description": "Response envelope for errors. `error` is required; `data` is absent.", - "properties": { - "request_id": { + "description": "Name of the user who created the rule." + }, + "updater_id": { + "type": "integer", + "format": "uint64", + "description": "ID of the user who last modified the rule." + }, + "updater_name": { "type": "string", - "example": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", - "description": "Unique trace ID of this request; include it when reporting issues so logs can be located." + "description": "Name of the user who last modified the rule." }, - "error": { - "$ref": "#/components/schemas/DutyError" + "created_at": { + "type": "integer", + "format": "int64", + "description": "Creation time, as a Unix timestamp in seconds." + }, + "updated_at": { + "type": "integer", + "format": "int64", + "description": "Last modification time, as a Unix timestamp in seconds." + }, + "triggered": { + "type": "boolean", + "description": "True if the rule currently has active alerts." + }, + "active_alert_count": { + "type": "integer", + "format": "int64", + "description": "Number of currently active (unrecovered) alerts fired by this rule. `triggered` equals `active_alert_count > 0`." + }, + "runtime_state": { + "type": "string", + "enum": [ + "disabled", + "offline", + "abnormal", + "stale", + "no_datasource", + "config_pending", + "waiting", + "normal" + ], + "description": "Runtime evaluation state, derived from edge heartbeats and the edge-reported rule status. Omitted when the state is unavailable.\n\n| Value | Meaning |\n|---|---|\n| `disabled` | The rule is disabled. |\n| `offline` | The edge instance or cluster owning this rule is offline. |\n| `abnormal` | The edge reports evaluation errors. |\n| `stale` | The edge's runtime status report is outdated. |\n| `no_datasource` | No datasource currently matches the rule's `ds_list` / `ds_ids`. |\n| `config_pending` | The latest rule config has not been delivered to the edge yet. |\n| `waiting` | Enabled, but the edge has not reported runtime status yet. |\n| `normal` | Evaluating normally. |" } - }, - "required": [ - "request_id", - "error" - ] + } }, - "IDRequest": { + "AlertRuleCounter": { "type": "object", + "description": "One historical snapshot of the account's alert rule total.", "required": [ - "id" + "id", + "account_id", + "num", + "clock" ], - "description": "Request with a single numeric ID.", "properties": { "id": { "type": "integer", "format": "uint64", - "description": "Numeric ID of the target resource; the exact meaning depends on the API being called (e.g. datasource ID, ruleset ID)." + "description": "ID of this snapshot record." + }, + "account_id": { + "type": "integer", + "format": "uint64", + "description": "ID of the account this snapshot belongs to." + }, + "num": { + "type": "integer", + "format": "int64", + "description": "Rule count at the sample time." + }, + "clock": { + "type": "integer", + "format": "int64", + "description": "Sample timestamp, Unix epoch seconds." } } }, - "NameMessage": { + "AlertRuleExport": { "type": "object", - "description": "Per-item result for batch rule operations.", + "description": "Portable alert rule representation for import/export. Omits identifying fields like `id`, `account_id`, and audit metadata.", "required": [ "name", - "message" + "ds_type", + "enabled", + "debug_log_enabled", + "cron_pattern" ], "properties": { "name": { "type": "string", - "description": "Rule name." + "description": "Rule name, up to 128 characters when imported." }, - "message": { + "labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom label key-value pairs attached to alert events produced by this rule." + }, + "ds_type": { "type": "string", - "description": "Empty on success, error message on failure." - } - } - }, - "RuleAuditListResponse": { - "type": "array", - "description": "Audit records for a rule, ordered by creation time descending. The `content` field is omitted.", - "items": { - "$ref": "#/components/schemas/AlertRuleAudit" - } - }, - "RuleBasicListResponse": { - "type": "array", - "items": { - "$ref": "#/components/schemas/AlertRuleBasic" - }, - "description": "List of alert rules (basic info)." - }, - "RuleConfigs": { - "type": "object", - "description": "Rule evaluation configuration.", - "properties": { - "queries": { + "description": "Datasource type ident, e.g. `prometheus`; must be a datasource type (`ident`) that exists in the import target environment." + }, + "ds_list": { "type": "array", "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Query identifier (letter, e.g. `A`). The name `R` is reserved and must not be used." - }, - "expr": { - "type": "string", - "description": "Query expression." - }, - "label_fields": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Result fields that become alert event labels — identical label sets collapse into one alert; must not overlap `value_fields`; applies to table-shaped results (SQL/ES-style datasources)." - }, - "value_fields": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Numeric result fields used in threshold evaluation (referenced as `$A.` in threshold expressions); required for threshold checks unless the datasource is `prometheus`/`loki`/`victorialogs`; field names must not contain `.`." - }, - "args": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Datasource-specific query options keyed by the `.