{ "openapi": "3.0.0", "info": { "title": "HyperDX External API", "description": "API for managing HyperDX alerts and dashboards", "version": "2.0.0" }, "servers": [ { "url": "/", "description": "Your HyperDX instance (http://:)" } ], "tags": [ { "name": "Dashboards", "description": "Endpoints for managing dashboards and their visualizations" }, { "name": "Alerts", "description": "Endpoints for managing monitoring alerts" }, { "name": "Charts", "description": "Endpoints for querying chart data" }, { "name": "Connections", "description": "Endpoints for managing ClickHouse connections" }, { "name": "Sources", "description": "Endpoints for managing data sources" }, { "name": "Webhooks", "description": "Endpoints for managing webhooks" }, { "name": "Search", "description": "Endpoints for querying raw data from log and trace sources" } ], "components": { "securitySchemes": { "BearerAuth": { "type": "http", "scheme": "bearer", "bearerFormat": "API Key" } }, "schemas": { "Error": { "type": "object", "properties": { "message": { "type": "string", "description": "Human-readable error message.", "example": "NOT_FOUND: Alert not found" } } }, "AlertInterval": { "type": "string", "enum": [ "1m", "5m", "15m", "30m", "1h", "6h", "12h", "1d" ], "description": "Evaluation interval." }, "AlertThresholdType": { "type": "string", "enum": [ "above", "below", "above_exclusive", "below_or_equal", "equal", "not_equal", "between", "not_between" ], "description": "Threshold comparison direction." }, "AlertSource": { "type": "string", "enum": [ "saved_search", "tile" ], "description": "Alert source type." }, "AlertState": { "type": "string", "enum": [ "ALERT", "OK", "INSUFFICIENT_DATA", "DISABLED", "PENDING" ], "description": "Current alert state." }, "AlertChannelType": { "type": "string", "enum": [ "webhook" ], "description": "Channel type." }, "AlertErrorType": { "type": "string", "enum": [ "QUERY_ERROR", "WEBHOOK_ERROR", "INVALID_ALERT", "UNKNOWN" ], "description": "Category of error recorded during alert execution." }, "AlertExecutionError": { "type": "object", "description": "An error recorded during a recent alert execution.", "required": [ "timestamp", "type", "message" ], "properties": { "timestamp": { "type": "string", "format": "date-time", "description": "When the error occurred.", "example": "2026-04-17T12:00:00.000Z" }, "type": { "$ref": "#/components/schemas/AlertErrorType", "description": "Category of the error.", "example": "QUERY_ERROR" }, "message": { "type": "string", "description": "Human-readable error message.", "example": "Query timed out after 30s" } } }, "AlertSilenced": { "type": "object", "description": "Silencing metadata.", "properties": { "by": { "type": "string", "description": "User ID who silenced the alert.", "nullable": true, "example": "65f5e4a3b9e77c001a234567" }, "at": { "type": "string", "description": "Silence start timestamp.", "format": "date-time", "example": "2026-03-19T08:00:00.000Z" }, "until": { "type": "string", "description": "Silence end timestamp.", "format": "date-time", "example": "2026-03-20T08:00:00.000Z" } } }, "AlertChannelWebhook": { "type": "object", "required": [ "type", "webhookId" ], "properties": { "type": { "$ref": "#/components/schemas/AlertChannelType", "description": "Channel type. Must be \"webhook\" for webhook alerts." }, "webhookId": { "type": "string", "description": "Webhook destination ID.", "example": "65f5e4a3b9e77c001a789012" } } }, "AlertChannel": { "oneOf": [ { "$ref": "#/components/schemas/AlertChannelWebhook" } ], "discriminator": { "propertyName": "type" } }, "Alert": { "type": "object", "properties": { "dashboardId": { "type": "string", "description": "Dashboard ID for tile-based alerts.", "nullable": true, "example": "65f5e4a3b9e77c001a567890" }, "tileId": { "type": "string", "description": "Tile ID for tile-based alerts. Must be a line, stacked bar, or number type tile.", "nullable": true, "example": "65f5e4a3b9e77c001a901234" }, "savedSearchId": { "type": "string", "description": "Saved search ID for saved_search alerts.", "nullable": true, "example": "65f5e4a3b9e77c001a345678" }, "groupBy": { "type": "string", "description": "Group-by key for saved search alerts.", "nullable": true, "example": "ServiceName" }, "threshold": { "type": "number", "description": "Threshold value for triggering the alert. For between and not_between threshold types, this is the lower bound.", "example": 100 }, "thresholdMax": { "type": "number", "nullable": true, "description": "Upper bound for between and not_between threshold types. Required when thresholdType is between or not_between, must be >= threshold.", "example": 500 }, "interval": { "$ref": "#/components/schemas/AlertInterval", "description": "Evaluation interval for the alert.", "example": "1h" }, "scheduleOffsetMinutes": { "type": "integer", "minimum": 0, "description": "Offset from the interval boundary in minutes. For example, 2 with a 5m interval evaluates windows at :02, :07, :12, etc. (UTC).", "nullable": true, "example": 2 }, "scheduleStartAt": { "type": "string", "format": "date-time", "description": "Absolute UTC start time anchor. Alert windows start from this timestamp and repeat every interval.", "nullable": true, "example": "2026-02-08T10:00:00.000Z" }, "source": { "$ref": "#/components/schemas/AlertSource", "description": "Alert source type (tile-based or saved search).", "example": "tile" }, "thresholdType": { "$ref": "#/components/schemas/AlertThresholdType", "description": "Threshold comparison direction.", "example": "above" }, "channel": { "$ref": "#/components/schemas/AlertChannel", "description": "Alert notification channel configuration." }, "name": { "type": "string", "description": "Human-friendly alert name.", "nullable": true, "example": "Test Alert" }, "message": { "type": "string", "description": "Alert message template.", "nullable": true, "example": "Test Alert Message" }, "note": { "type": "string", "description": "Freeform note for the alert. Supports markdown formatting.", "nullable": true, "minLength": 1, "maxLength": 4096, "example": "Threshold raised from 50 to 100 on 2026-01-15. See [runbook](https://wiki.example.com/runbook)." }, "numConsecutiveWindows": { "type": "integer", "minimum": 1, "nullable": true, "description": "Fire the alert only after its condition has been met for this many consecutive evaluation windows. While the condition is met but fewer than this many consecutive windows have violated, the alert is in the PENDING state.", "example": 3 } } }, "AlertResponse": { "allOf": [ { "$ref": "#/components/schemas/Alert" }, { "type": "object", "properties": { "id": { "type": "string", "description": "Unique alert identifier.", "example": "65f5e4a3b9e77c001a123456" }, "state": { "$ref": "#/components/schemas/AlertState", "description": "Current alert state.", "example": "ALERT" }, "teamId": { "type": "string", "description": "Team identifier.", "example": "65f5e4a3b9e77c001a345678" }, "silenced": { "$ref": "#/components/schemas/AlertSilenced", "description": "Silencing metadata.", "nullable": true }, "executionErrors": { "type": "array", "nullable": true, "description": "Errors recorded during the most recent alert execution, if any.", "items": { "$ref": "#/components/schemas/AlertExecutionError" } }, "createdAt": { "type": "string", "nullable": true, "format": "date-time", "description": "Creation timestamp.", "example": "2023-01-01T00:00:00.000Z" }, "updatedAt": { "type": "string", "nullable": true, "format": "date-time", "description": "Last update timestamp.", "example": "2023-01-01T00:00:00.000Z" } } } ] }, "CreateAlertRequest": { "allOf": [ { "$ref": "#/components/schemas/Alert" }, { "type": "object", "required": [ "threshold", "interval", "thresholdType", "channel" ] } ] }, "UpdateAlertRequest": { "allOf": [ { "$ref": "#/components/schemas/Alert" }, { "type": "object", "required": [ "threshold", "interval", "thresholdType", "channel" ] } ] }, "AlertResponseEnvelope": { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/AlertResponse", "description": "The alert object." } } }, "AlertsListResponse": { "type": "object", "required": [ "data", "meta" ], "properties": { "data": { "type": "array", "description": "List of alert objects.", "items": { "$ref": "#/components/schemas/AlertResponse" } }, "meta": { "$ref": "#/components/schemas/PaginationMeta", "description": "Pagination metadata for this result page." } } }, "EmptyResponse": { "type": "object", "properties": {} }, "ChartSeries": { "type": "object", "required": [ "sourceId", "aggFn", "where", "groupBy" ], "properties": { "sourceId": { "type": "string", "description": "ID of the data source for this series", "example": "65f5e4a3b9e77c001a123456" }, "aggFn": { "type": "string", "description": "Aggregation function to use on the data", "enum": [ "avg", "count", "count_distinct", "last_value", "max", "min", "quantile", "sum" ], "example": "count" }, "field": { "type": "string", "description": "Field to aggregate", "example": "duration" }, "where": { "type": "string", "description": "Filter condition in Lucene query syntax", "example": "service:api AND level:error" }, "whereLanguage": { "type": "string", "description": "Query language used in the where clause", "enum": [ "lucene", "sql" ], "example": "lucene" }, "groupBy": { "type": "array", "description": "Fields to group the results by", "items": { "type": "string" }, "example": [ "service", "host" ] }, "metricName": { "type": "string", "description": "Name of the metric (for metric data sources)", "example": "http_requests_total" }, "metricDataType": { "type": "string", "description": "Type of metric data", "enum": [ "sum", "gauge", "histogram" ], "example": "gauge" } } }, "SeriesQueryRequest": { "type": "object", "required": [ "series", "startTime", "endTime" ], "properties": { "series": { "type": "array", "description": "Array of series configurations", "items": { "$ref": "#/components/schemas/ChartSeries" }, "minItems": 1, "maxItems": 5 }, "startTime": { "type": "number", "description": "Start timestamp in milliseconds", "example": 1647014400000 }, "endTime": { "type": "number", "description": "End timestamp in milliseconds", "example": 1647100800000 }, "granularity": { "type": "string", "description": "Time bucket size for aggregations", "enum": [ "30s", "1m", "5m", "10m", "15m", "30m", "1h", "2h", "6h", "12h", "1d", "2d", "7d", "30d", "auto" ], "example": "1h" }, "seriesReturnType": { "type": "string", "description": "Format of the returned data", "enum": [ "ratio", "column" ], "example": "column" } } }, "SeriesDataPoint": { "type": "object", "properties": { "ts_bucket": { "type": "number", "description": "Timestamp of the data point (bucket start time)", "example": 1647014400000 }, "series_0.data": { "type": "number", "description": "Value for the first series", "example": 42 }, "series_1.data": { "type": "number", "description": "Value for the second series", "example": 18 }, "group": { "type": "array", "description": "Group by values if groupBy was specified", "items": { "type": "string" }, "example": [ "api", "prod-host-1" ] } } }, "SeriesResponse": { "type": "object", "properties": { "data": { "type": "array", "description": "Array of data points for the series", "items": { "$ref": "#/components/schemas/SeriesDataPoint" } } } }, "Connection": { "type": "object", "required": [ "id", "name", "host", "username" ], "properties": { "id": { "type": "string", "description": "Unique connection ID.", "example": "507f1f77bcf86cd799439012" }, "name": { "type": "string", "description": "Display name for the connection.", "example": "Production ClickHouse" }, "host": { "type": "string", "description": "ClickHouse HTTP endpoint URL.", "example": "https://clickhouse.example.com:8443" }, "username": { "type": "string", "description": "ClickHouse username.", "example": "default" }, "hyperdxSettingPrefix": { "type": "string", "description": "Optional prefix for HyperDX-specific ClickHouse settings. Must only contain alphanumeric characters and underscores.", "nullable": true, "example": "hyperdx_" }, "isPrometheusEndpoint": { "type": "boolean", "description": "Optional. When true, `host` is treated as a Prometheus-compatible API endpoint (e.g. Prometheus or Thanos) and PromQL queries are proxied to it. When false or omitted, `host` is a ClickHouse HTTP endpoint.", "example": false }, "createdAt": { "type": "string", "format": "date-time", "description": "Creation timestamp", "example": "2025-01-01T00:00:00.000Z" }, "updatedAt": { "type": "string", "format": "date-time", "description": "Last update timestamp", "example": "2025-06-15T10:30:00.000Z" } } }, "CreateConnectionRequest": { "type": "object", "required": [ "name", "host", "username" ], "properties": { "name": { "type": "string", "description": "Display name for the connection.", "example": "Production ClickHouse" }, "host": { "type": "string", "description": "ClickHouse HTTP endpoint URL.", "example": "https://clickhouse.example.com:8443" }, "username": { "type": "string", "description": "ClickHouse username.", "example": "default" }, "password": { "type": "string", "writeOnly": true, "description": "ClickHouse password. Never returned by the API.", "example": "my-secret-password" }, "hyperdxSettingPrefix": { "type": "string", "description": "Optional prefix for HyperDX-specific ClickHouse settings. Must only contain alphanumeric characters and underscores.", "nullable": true, "example": "hyperdx_" }, "isPrometheusEndpoint": { "type": "boolean", "description": "Optional. When true, `host` is treated as a Prometheus-compatible API endpoint (e.g. Prometheus or Thanos) and PromQL queries are proxied to it. When false or omitted, `host` is a ClickHouse HTTP endpoint.", "example": false } } }, "UpdateConnectionRequest": { "type": "object", "required": [ "name", "host", "username" ], "properties": { "name": { "type": "string", "description": "Display name for the connection.", "example": "Production ClickHouse" }, "host": { "type": "string", "description": "ClickHouse HTTP endpoint URL.", "example": "https://clickhouse.example.com:8443" }, "username": { "type": "string", "description": "ClickHouse username.", "example": "default" }, "password": { "type": "string", "writeOnly": true, "description": "ClickHouse password. If omitted or empty, the existing password is kept.", "example": "my-new-secret-password" }, "hyperdxSettingPrefix": { "type": "string", "description": "Optional prefix for HyperDX-specific ClickHouse settings. Set to null or an empty string to clear the existing value. If omitted, the existing value is kept.", "nullable": true, "example": "hyperdx_" }, "isPrometheusEndpoint": { "type": "boolean", "description": "Optional. When true, `host` is treated as a Prometheus-compatible API endpoint. When false or omitted, `host` is a ClickHouse HTTP endpoint. Omit to keep the existing value unchanged.", "example": false } } }, "ConnectionResponseEnvelope": { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/Connection", "description": "The connection object." } } }, "ConnectionsListResponse": { "type": "object", "properties": { "data": { "type": "array", "description": "List of connection objects.", "items": { "$ref": "#/components/schemas/Connection" } }, "meta": { "type": "object", "description": "Present only when one or more stored connections could not be serialized and were omitted from `data`.", "properties": { "skipped": { "type": "integer", "description": "Number of connections omitted from the response because they failed serialization.", "example": 1 }, "skippedIds": { "type": "array", "description": "IDs of the connections that were omitted.", "items": { "type": "string" }, "example": [ "507f1f77bcf86cd799439012" ] } } } } }, "NumberFormatOutput": { "type": "string", "enum": [ "currency", "percent", "byte", "time", "number", "data_rate", "throughput", "duration" ], "description": "Output format type (currency, percent, byte, time, number, data_rate, throughput, duration)." }, "AggregationFunction": { "type": "string", "enum": [ "avg", "count", "count_distinct", "last_value", "max", "min", "quantile", "sum", "any", "none" ], "description": "Aggregation function to apply to the field or metric value." }, "QueryLanguage": { "type": "string", "enum": [ "sql", "lucene" ], "description": "Query language for the where clause." }, "SavedFilterValue": { "type": "object", "required": [ "condition" ], "properties": { "type": { "type": "string", "enum": [ "sql" ], "default": "sql", "description": "Filter type. Currently only \"sql\" is supported.", "example": "sql" }, "condition": { "type": "string", "description": "SQL filter condition. For example use expressions in the form \"column IN ('value')\".", "example": "ServiceName IN ('hdx-oss-dev-api')" } } }, "MetricDataType": { "type": "string", "enum": [ "sum", "gauge", "histogram", "summary", "exponential histogram" ], "description": "Metric data type, only for metrics data sources." }, "TimeSeriesDisplayType": { "type": "string", "enum": [ "stacked_bar", "line" ], "description": "Visual representation type for the time series." }, "QuantileLevel": { "type": "number", "enum": [ 0.5, 0.9, 0.95, 0.99 ], "description": "Percentile level; only valid when aggFn is \"quantile\"." }, "SortOrder": { "type": "string", "enum": [ "desc", "asc" ], "description": "Sort order for table rows." }, "NumberFormat": { "type": "object", "properties": { "output": { "$ref": "#/components/schemas/NumberFormatOutput", "description": "Output format applied to the number.", "example": "number" }, "mantissa": { "type": "integer", "description": "Number of decimal places.", "example": 2 }, "thousandSeparated": { "type": "boolean", "description": "Whether to use thousand separators.", "example": true }, "average": { "type": "boolean", "description": "Whether to show as average.", "example": false }, "decimalBytes": { "type": "boolean", "description": "Use decimal bytes (1000) vs binary bytes (1024).", "example": false }, "factor": { "type": "number", "description": "Multiplication factor.", "example": 1 }, "currencySymbol": { "type": "string", "description": "Currency symbol for currency format.", "example": "$" }, "numericUnit": { "type": "string", "enum": [ "bytes_iec", "bytes_si", "bits_iec", "bits_si", "kibibytes", "kilobytes", "mebibytes", "megabytes", "gibibytes", "gigabytes", "tebibytes", "terabytes", "pebibytes", "petabytes", "packets_sec", "bytes_sec_iec", "bytes_sec_si", "bits_sec_iec", "bits_sec_si", "kibibytes_sec", "kibibits_sec", "kilobytes_sec", "kilobits_sec", "mebibytes_sec", "mebibits_sec", "megabytes_sec", "megabits_sec", "gibibytes_sec", "gibibits_sec", "gigabytes_sec", "gigabits_sec", "tebibytes_sec", "tebibits_sec", "terabytes_sec", "terabits_sec", "pebibytes_sec", "pebibits_sec", "petabytes_sec", "petabits_sec", "cps", "ops", "rps", "reads_sec", "wps", "iops", "cpm", "opm", "rpm_reads", "wpm" ], "description": "Numeric unit for data, data rate, or throughput formats.", "example": "bytes_iec" }, "unit": { "type": "string", "description": "Custom unit label.", "example": "ms" } } }, "ChartPaletteToken": { "type": "string", "enum": [ "chart-blue", "chart-orange", "chart-red", "chart-cyan", "chart-green", "chart-pink", "chart-purple", "chart-light-blue", "chart-brown", "chart-gray", "chart-success", "chart-warning", "chart-error" ], "description": "Palette token used to color a number tile. Tokens reflow across light and dark themes, so raw hex values are not accepted.\n", "example": "chart-red" }, "BackgroundChart": { "type": "object", "required": [ "type" ], "description": "Optional background trend sparkline drawn behind a number tile's value, derived from a time-bucketed version of the tile's query. Builder number tiles only (raw SQL number tiles have no time dimension to bucket).\n", "properties": { "type": { "type": "string", "enum": [ "line", "area" ], "description": "Sparkline shape.", "example": "line" }, "color": { "$ref": "#/components/schemas/ChartPaletteToken", "description": "Optional palette-token override for the sparkline. When unset the sparkline inherits the tile's static color.\n" } } }, "NumericColorCondition": { "type": "object", "required": [ "operator", "value", "color" ], "description": "Color rule comparing the displayed value against a single numeric bound.", "properties": { "operator": { "type": "string", "enum": [ "gt", "gte", "lt", "lte" ], "description": "Numeric comparison operator.", "example": "gt" }, "value": { "type": "number", "description": "Numeric bound the displayed value is compared against. Only finite numbers are accepted (Infinity and NaN are rejected).\n", "example": 100 }, "color": { "$ref": "#/components/schemas/ChartPaletteToken", "description": "Color applied when the rule matches." }, "label": { "type": "string", "maxLength": 40, "description": "Optional label describing the rule.", "example": "High" } } }, "BetweenColorCondition": { "type": "object", "required": [ "operator", "value", "color" ], "description": "Color rule matching when the displayed value falls within an inclusive range.", "properties": { "operator": { "type": "string", "enum": [ "between" ], "description": "Range comparison operator.", "example": "between" }, "value": { "type": "array", "minItems": 2, "maxItems": 2, "items": { "type": "number" }, "description": "Inclusive [min, max] range. Both bounds must be finite numbers.\n", "example": [ 100, 500 ] }, "color": { "$ref": "#/components/schemas/ChartPaletteToken", "description": "Color applied when the rule matches." }, "label": { "type": "string", "maxLength": 40, "description": "Optional label describing the rule.", "example": "Warning" } } }, "EqualityColorCondition": { "type": "object", "required": [ "operator", "value", "color" ], "description": "Color rule matching when the displayed value equals (eq) or does not equal (neq) a number or string.", "properties": { "operator": { "type": "string", "enum": [ "eq", "neq" ], "description": "Equality comparison operator.", "example": "eq" }, "value": { "oneOf": [ { "type": "number" }, { "type": "string", "maxLength": 200 } ], "description": "A finite number, or a string up to 200 characters, to compare for equality.\n", "example": "OK" }, "color": { "$ref": "#/components/schemas/ChartPaletteToken", "description": "Color applied when the rule matches." }, "label": { "type": "string", "maxLength": 40, "description": "Optional label describing the rule.", "example": "Healthy" } } }, "NumberTileColorCondition": { "description": "A single conditional color rule for a number tile. Rules are evaluated in order and the last matching rule wins. When no rule matches, the static color applies, then the default text color. The number-tile editor surfaces numeric and equality operators only.\n", "oneOf": [ { "$ref": "#/components/schemas/NumericColorCondition" }, { "$ref": "#/components/schemas/BetweenColorCondition" }, { "$ref": "#/components/schemas/EqualityColorCondition" } ], "discriminator": { "propertyName": "operator", "mapping": { "gt": "#/components/schemas/NumericColorCondition", "gte": "#/components/schemas/NumericColorCondition", "lt": "#/components/schemas/NumericColorCondition", "lte": "#/components/schemas/NumericColorCondition", "between": "#/components/schemas/BetweenColorCondition", "eq": "#/components/schemas/EqualityColorCondition", "neq": "#/components/schemas/EqualityColorCondition" } } }, "TimeChartSeries": { "type": "object", "required": [ "type", "sourceId", "aggFn", "where", "whereLanguage", "groupBy" ], "properties": { "type": { "type": "string", "enum": [ "time" ], "description": "Series type discriminator. Must be \"time\" for time-series charts.", "example": "time" }, "sourceId": { "type": "string", "description": "ID of the data source to query", "example": "65f5e4a3b9e77c001a567890" }, "aggFn": { "$ref": "#/components/schemas/AggregationFunction", "description": "Aggregation function to apply to the field or metric value", "example": "count" }, "level": { "type": "number", "minimum": 0, "maximum": 1, "description": "Percentile level for quantile aggregations (e.g., 0.95 for p95)", "example": 0.95 }, "field": { "type": "string", "description": "Column or expression to aggregate (required for most aggregation functions except count)", "example": "duration" }, "alias": { "type": "string", "description": "Display name for the series in the chart", "example": "Request Duration" }, "where": { "type": "string", "description": "Filter query for the data (syntax depends on whereLanguage)", "example": "service:api" }, "whereLanguage": { "$ref": "#/components/schemas/QueryLanguage", "description": "Query language for the where clause", "example": "lucene" }, "groupBy": { "type": "array", "items": { "type": "string" }, "maxItems": 10, "description": "Fields to group results by (creates separate series for each group)", "example": [ "host" ] }, "numberFormat": { "$ref": "#/components/schemas/NumberFormat", "description": "Number formatting options for displayed values." }, "metricDataType": { "$ref": "#/components/schemas/MetricDataType", "description": "Metric data type, only for metrics data sources.", "example": "sum" }, "metricName": { "type": "string", "description": "Metric name for metrics data sources", "example": "http.server.duration" }, "displayType": { "$ref": "#/components/schemas/TimeSeriesDisplayType", "description": "Visual representation type for the time series", "example": "line" } } }, "TableChartSeries": { "type": "object", "required": [ "type", "sourceId", "aggFn", "where", "whereLanguage", "groupBy" ], "properties": { "type": { "type": "string", "enum": [ "table" ], "description": "Series type discriminator. Must be \"table\" for table charts.", "example": "table" }, "sourceId": { "type": "string", "description": "ID of the data source to query", "example": "65f5e4a3b9e77c001a567890" }, "aggFn": { "$ref": "#/components/schemas/AggregationFunction", "description": "Aggregation function to apply to the field or metric value", "example": "count" }, "level": { "type": "number", "minimum": 0, "maximum": 1, "description": "Percentile level for quantile aggregations (e.g., 0.95 for p95)", "example": 0.95 }, "field": { "type": "string", "description": "Column or expression to aggregate (required for most aggregation functions except count)", "example": "duration" }, "alias": { "type": "string", "description": "Display name for the series", "example": "Total Count" }, "where": { "type": "string", "description": "Filter query for the data (syntax depends on whereLanguage)", "example": "level:error" }, "whereLanguage": { "$ref": "#/components/schemas/QueryLanguage", "description": "Query language for the where clause", "example": "lucene" }, "groupBy": { "type": "array", "items": { "type": "string" }, "maxItems": 10, "description": "Fields to group results by (creates separate rows for each group)", "example": [ "errorType" ] }, "sortOrder": { "$ref": "#/components/schemas/SortOrder", "description": "Sort order for table rows", "example": "desc" }, "numberFormat": { "$ref": "#/components/schemas/NumberFormat", "description": "Number formatting options for displayed values." }, "metricDataType": { "$ref": "#/components/schemas/MetricDataType", "description": "Metric data type, only for metrics data sources.", "example": "sum" }, "metricName": { "type": "string", "description": "Metric name for metrics data sources", "example": "http.server.duration" } } }, "NumberChartSeries": { "type": "object", "required": [ "type", "sourceId", "aggFn", "where", "whereLanguage" ], "properties": { "type": { "type": "string", "enum": [ "number" ], "description": "Series type discriminator. Must be \"number\" for single-value number charts.", "example": "number" }, "sourceId": { "type": "string", "description": "ID of the data source to query", "example": "65f5e4a3b9e77c001a567890" }, "aggFn": { "$ref": "#/components/schemas/AggregationFunction", "description": "Aggregation function to apply to the field or metric value", "example": "count" }, "level": { "type": "number", "minimum": 0, "maximum": 1, "description": "Percentile level for quantile aggregations (e.g., 0.95 for p95)", "example": 0.95 }, "field": { "type": "string", "description": "Column or expression to aggregate (required for most aggregation functions except count)", "example": "duration" }, "alias": { "type": "string", "description": "Display name for the series in the chart", "example": "Total Requests" }, "where": { "type": "string", "description": "Filter query for the data (syntax depends on whereLanguage)", "example": "service:api" }, "whereLanguage": { "$ref": "#/components/schemas/QueryLanguage", "description": "Query language for the where clause", "example": "lucene" }, "numberFormat": { "$ref": "#/components/schemas/NumberFormat", "description": "Number formatting options for displayed values." }, "metricDataType": { "$ref": "#/components/schemas/MetricDataType", "description": "Metric data type, only for metrics data sources.", "example": "sum" }, "metricName": { "type": "string", "description": "Metric name for metrics data sources.", "example": "http.server.duration" } } }, "SearchChartSeries": { "type": "object", "required": [ "type", "sourceId", "fields", "where", "whereLanguage" ], "properties": { "type": { "type": "string", "enum": [ "search" ], "description": "Series type discriminator. Must be \"search\" for search/log viewer charts.", "example": "search" }, "sourceId": { "type": "string", "description": "ID of the data source to query", "example": "65f5e4a3b9e77c001a567890" }, "fields": { "type": "array", "items": { "type": "string" }, "description": "List of field names to display in the search results table", "example": [ "timestamp", "level", "message" ] }, "where": { "type": "string", "description": "Filter query for the data (syntax depends on whereLanguage)", "example": "level:error" }, "whereLanguage": { "$ref": "#/components/schemas/QueryLanguage", "description": "Query language for the where clause", "example": "lucene" } } }, "MarkdownChartSeries": { "type": "object", "required": [ "type", "content" ], "properties": { "type": { "type": "string", "enum": [ "markdown" ], "description": "Series type discriminator. Must be \"markdown\" for markdown text widgets.", "example": "markdown" }, "content": { "type": "string", "description": "Markdown content to render inside the widget.", "example": "# Dashboard Title\n\nThis is a markdown widget.", "maxLength": 100000 } } }, "DashboardChartSeries": { "oneOf": [ { "$ref": "#/components/schemas/TimeChartSeries" }, { "$ref": "#/components/schemas/TableChartSeries" }, { "$ref": "#/components/schemas/NumberChartSeries" }, { "$ref": "#/components/schemas/SearchChartSeries" }, { "$ref": "#/components/schemas/MarkdownChartSeries" } ], "discriminator": { "propertyName": "type", "mapping": { "time": "#/components/schemas/TimeChartSeries", "table": "#/components/schemas/TableChartSeries", "number": "#/components/schemas/NumberChartSeries", "search": "#/components/schemas/SearchChartSeries", "markdown": "#/components/schemas/MarkdownChartSeries" } } }, "SelectItem": { "type": "object", "required": [ "aggFn" ], "description": "A single aggregated value to compute. The valueExpression must be omitted when aggFn is \"count\", and required for all other functions. The level field may only be used with aggFn \"quantile\".\n", "properties": { "aggFn": { "$ref": "#/components/schemas/AggregationFunction", "description": "Aggregation function to apply. \"count\" does not require a valueExpression; \"quantile\" requires a level field indicating the desired percentile (e.g., 0.95).\n", "example": "count" }, "valueExpression": { "type": "string", "maxLength": 10000, "description": "Expression for the column or value to aggregate. Must be omitted when aggFn is \"count\"; required for all other aggFn values.\n", "example": "Duration" }, "alias": { "type": "string", "maxLength": 10000, "description": "Display alias for this select item in chart legends.", "example": "Request Duration" }, "level": { "$ref": "#/components/schemas/QuantileLevel", "description": "Percentile level; only valid when aggFn is \"quantile\"." }, "where": { "type": "string", "maxLength": 10000, "description": "SQL or Lucene filter condition applied before aggregation.", "default": "", "example": "service:api" }, "whereLanguage": { "$ref": "#/components/schemas/QueryLanguage", "description": "Query language for the where clause." }, "metricName": { "type": "string", "description": "Name of the metric to aggregate; only applicable when the source is a metrics source.", "example": "http.server.duration" }, "metricType": { "$ref": "#/components/schemas/MetricDataType", "description": "Metric type; only applicable when the source is a metrics source." }, "periodAggFn": { "type": "string", "enum": [ "delta" ], "description": "Optional period aggregation function for Gauge metrics (e.g., compute the delta over the period).", "example": "delta" }, "numberFormat": { "$ref": "#/components/schemas/NumberFormat", "description": "Per-series number formatting options. When set, takes precedence over the chart-level numberFormat for this select item only.\n" } } }, "LineBuilderChartConfig": { "type": "object", "required": [ "displayType", "sourceId", "select" ], "description": "Builder configuration for a line time-series chart.", "properties": { "displayType": { "type": "string", "enum": [ "line" ], "description": "Display type discriminator. Must be \"line\" for line charts.", "example": "line" }, "sourceId": { "type": "string", "description": "ID of the data source to query.", "example": "65f5e4a3b9e77c001a111111" }, "select": { "type": "array", "minItems": 1, "maxItems": 20, "description": "One or more aggregated values to plot. When asRatio is true, exactly two select items are required.\n", "items": { "$ref": "#/components/schemas/SelectItem" } }, "groupBy": { "type": "string", "description": "Field expression to group results by (creates separate lines per group value).", "example": "host", "maxLength": 10000 }, "asRatio": { "type": "boolean", "description": "Plot select[0] / select[1] as a ratio. Requires exactly two select items.", "default": false }, "alignDateRangeToGranularity": { "type": "boolean", "description": "Expand date range boundaries to the query granularity interval.", "default": true }, "fillNulls": { "type": "boolean", "description": "Fill missing time buckets with zero instead of leaving gaps.", "default": true }, "fitYAxisToData": { "type": "boolean", "description": "Set the y-axis lower bound to the minimum of the displayed data instead of zero, making small fluctuations between series easier to see.\n", "default": false }, "numberFormat": { "$ref": "#/components/schemas/NumberFormat", "description": "Number formatting options for displayed values." }, "compareToPreviousPeriod": { "type": "boolean", "description": "Overlay the equivalent previous time period for comparison.", "default": false } } }, "BarBuilderChartConfig": { "type": "object", "required": [ "displayType", "sourceId", "select" ], "description": "Builder configuration for a stacked-bar time-series chart.", "properties": { "displayType": { "type": "string", "enum": [ "stacked_bar" ], "description": "Display type discriminator. Must be \"stacked_bar\" for stacked-bar charts.", "example": "stacked_bar" }, "sourceId": { "type": "string", "description": "ID of the data source to query.", "example": "65f5e4a3b9e77c001a111111" }, "select": { "type": "array", "minItems": 1, "maxItems": 20, "description": "One or more aggregated values to plot. When asRatio is true, exactly two select items are required.\n", "items": { "$ref": "#/components/schemas/SelectItem" } }, "groupBy": { "type": "string", "description": "Field expression to group results by (creates separate bars segments per group value).", "example": "service", "maxLength": 10000 }, "asRatio": { "type": "boolean", "description": "Plot select[0] / select[1] as a ratio. Requires exactly two select items.", "default": false }, "alignDateRangeToGranularity": { "type": "boolean", "description": "Align the date range boundaries to the query granularity interval.", "default": true }, "fillNulls": { "type": "boolean", "description": "Fill missing time buckets with zero instead of leaving gaps.", "default": true }, "numberFormat": { "$ref": "#/components/schemas/NumberFormat", "description": "Number formatting options for displayed values." } } }, "TableBuilderChartConfig": { "type": "object", "required": [ "displayType", "sourceId", "select" ], "description": "Builder configuration for a table aggregation chart.", "properties": { "displayType": { "type": "string", "enum": [ "table" ], "description": "Display type discriminator. Must be \"table\" for table charts.", "example": "table" }, "sourceId": { "type": "string", "description": "ID of the data source to query.", "example": "65f5e4a3b9e77c001a111111" }, "select": { "type": "array", "minItems": 1, "maxItems": 20, "description": "One or more aggregated values to display as table columns. When asRatio is true, exactly two select items are required.\n", "items": { "$ref": "#/components/schemas/SelectItem" } }, "groupBy": { "type": "string", "maxLength": 10000, "description": "Field expression to group results by (one row per group value).", "example": "service" }, "having": { "type": "string", "maxLength": 10000, "description": "Post-aggregation SQL HAVING condition.", "example": "count > 100" }, "orderBy": { "type": "string", "maxLength": 10000, "description": "SQL ORDER BY expression for sorting table rows.", "example": "count DESC" }, "asRatio": { "type": "boolean", "description": "Display select[0] / select[1] as a ratio. Requires exactly two select items.", "example": false }, "numberFormat": { "$ref": "#/components/schemas/NumberFormat", "description": "Number formatting options for displayed values." }, "groupByColumnsOnLeft": { "type": "boolean", "description": "When true, render Group By columns to the left of series columns in the table. Defaults to false (Group By columns on the right).\n", "default": false, "example": false }, "onClick": { "$ref": "#/components/schemas/OnClick", "description": "Optional link-out configuration applied when a user clicks a row." } } }, "NumberBuilderChartConfig": { "type": "object", "required": [ "displayType", "sourceId", "select" ], "description": "Builder configuration for a single big-number chart.", "properties": { "displayType": { "type": "string", "enum": [ "number" ], "description": "Display type discriminator. Must be \"number\" for single big-number charts.", "example": "number" }, "sourceId": { "type": "string", "description": "ID of the data source to query.", "example": "65f5e4a3b9e77c001a111111" }, "select": { "type": "array", "minItems": 1, "maxItems": 1, "description": "Exactly one aggregated value to display as a single number.", "items": { "$ref": "#/components/schemas/SelectItem" } }, "numberFormat": { "$ref": "#/components/schemas/NumberFormat", "description": "Number formatting options for displayed values." }, "color": { "$ref": "#/components/schemas/ChartPaletteToken", "description": "Optional static color applied to the displayed number." }, "colorRules": { "type": "array", "maxItems": 10, "description": "Ordered conditional color rules evaluated against the displayed value (last match wins). Falls back to color, then the default text color when no rule matches.\n", "items": { "$ref": "#/components/schemas/NumberTileColorCondition" } }, "backgroundChart": { "$ref": "#/components/schemas/BackgroundChart", "description": "Optional background trend sparkline drawn behind the value.\n" } } }, "PieBuilderChartConfig": { "type": "object", "required": [ "displayType", "sourceId", "select" ], "description": "Builder configuration for a pie chart tile. Each slice represents one group value.", "properties": { "displayType": { "type": "string", "enum": [ "pie" ], "description": "Display type discriminator. Must be \"pie\" for pie charts.", "example": "pie" }, "sourceId": { "type": "string", "description": "ID of the data source to query.", "example": "65f5e4a3b9e77c001a111111" }, "select": { "type": "array", "minItems": 1, "maxItems": 1, "description": "Exactly one aggregated value used to size each pie slice.", "items": { "$ref": "#/components/schemas/SelectItem" } }, "groupBy": { "type": "string", "maxLength": 10000, "description": "Field expression to group results by (one slice per group value).", "example": "service" }, "orderBy": { "type": "string", "maxLength": 10000, "description": "Optional custom SQL ORDER BY expression (raw SQL). Overrides the default value-descending ordering and, when combined with \"limit\", controls which slices are kept.\n", "example": "\"Count\" DESC" }, "numberFormat": { "$ref": "#/components/schemas/NumberFormat", "description": "Number formatting options for displayed values." }, "limit": { "type": "integer", "minimum": 1, "description": "Maximum number of slices (SQL LIMIT). Without a custom \"orderBy\" the query keeps the groups with the largest aggregated values; with an \"orderBy\" it keeps the first slices in that order. Omit to fetch all groups.\n", "example": 10 } } }, "CategoricalBarBuilderChartConfig": { "type": "object", "required": [ "displayType", "sourceId", "select" ], "description": "Builder configuration for a categorical bar chart tile. Each bar represents one group value. Distinct from stacked_bar, which is a time-series chart.\n", "properties": { "displayType": { "type": "string", "enum": [ "bar" ], "description": "Display type discriminator. Must be \"bar\" for categorical bar charts.", "example": "bar" }, "sourceId": { "type": "string", "description": "ID of the data source to query.", "example": "65f5e4a3b9e77c001a111111" }, "select": { "type": "array", "minItems": 1, "maxItems": 1, "description": "Exactly one aggregated value used to size each bar.", "items": { "$ref": "#/components/schemas/SelectItem" } }, "groupBy": { "type": "string", "maxLength": 10000, "description": "Field expression to group results by (one bar per group value).", "example": "service" }, "orderBy": { "type": "string", "maxLength": 10000, "description": "Optional custom SQL ORDER BY expression (raw SQL). Overrides the default value-descending ordering and, when combined with \"limit\", controls which bars are kept.\n", "example": "\"Count\" DESC" }, "numberFormat": { "$ref": "#/components/schemas/NumberFormat", "description": "Number formatting options for displayed values." }, "limit": { "type": "integer", "minimum": 1, "description": "Maximum number of bars (SQL LIMIT). Without a custom \"orderBy\" the query keeps the groups with the largest aggregated values; with an \"orderBy\" it keeps the first bars in that order. Omit to fetch all groups.\n", "example": 10 } } }, "HeatmapSelectItem": { "type": "object", "required": [ "valueExpression" ], "description": "Single select item for a heatmap tile. The value being bucketed is provided in valueExpression and the count contributing to each bucket in countExpression. The heatmap-specific fields (countExpression, heatmapScaleType) are persisted on the select item, not the chart config. The chart-level discriminator is the HeatmapChartConfig's `displayType: \"heatmap\"`; no aggregation function or alias is exposed on this select item because the heatmap aggregation function is fixed internally and the HeatmapSeriesEditor does not render an alias input.\n", "properties": { "valueExpression": { "type": "string", "minLength": 1, "maxLength": 10000, "description": "SQL expression for the value being bucketed on the y-axis. Must be non-empty.", "example": "Duration" }, "countExpression": { "type": "string", "maxLength": 10000, "description": "SQL expression for the count contributing to each bucket. Defaults to \"count()\" in the editor when omitted.\n", "example": "count()" }, "heatmapScaleType": { "type": "string", "enum": [ "log", "linear" ], "description": "Scale type used to bucket values on the y-axis.", "example": "log" } } }, "HeatmapChartConfig": { "type": "object", "required": [ "displayType", "sourceId", "select" ], "description": "Builder configuration for a heatmap tile. Heatmap is builder-only (no Raw SQL variant) and currently supports trace sources. The row-level filter lives at the chart-config level (where / whereLanguage), matching the HeatmapSeriesEditor in the UI.\n", "properties": { "displayType": { "type": "string", "enum": [ "heatmap" ], "description": "Display type discriminator. Must be \"heatmap\" for heatmap tiles.", "example": "heatmap" }, "sourceId": { "type": "string", "description": "ID of the data source to query.", "example": "65f5e4a3b9e77c001a111111" }, "select": { "type": "array", "minItems": 1, "maxItems": 1, "description": "Exactly one heatmap select item.", "items": { "$ref": "#/components/schemas/HeatmapSelectItem" } }, "where": { "type": "string", "maxLength": 10000, "description": "Row-level filter (syntax depends on whereLanguage).", "default": "", "example": "ServiceName = 'api'" }, "whereLanguage": { "$ref": "#/components/schemas/QueryLanguage", "description": "Query language for the where clause.", "default": "lucene" }, "numberFormat": { "$ref": "#/components/schemas/NumberFormat", "description": "Number formatting options for displayed values." } } }, "SearchChartConfig": { "type": "object", "required": [ "displayType", "sourceId", "select", "whereLanguage" ], "description": "Configuration for a raw-event search / log viewer tile.", "properties": { "displayType": { "type": "string", "enum": [ "search" ], "description": "Display type discriminator. Must be \"search\" for search/log viewer tiles.", "example": "search" }, "sourceId": { "type": "string", "description": "ID of the data source to query.", "example": "65f5e4a3b9e77c001a111111" }, "select": { "type": "string", "maxLength": 10000, "description": "Comma-separated list of expressions to display.", "example": "timestamp, level, message" }, "where": { "type": "string", "maxLength": 10000, "description": "Filter condition for the search (syntax depends on whereLanguage).", "default": "", "example": "level:error" }, "whereLanguage": { "$ref": "#/components/schemas/QueryLanguage", "description": "Query language for the where clause." } } }, "EventPatternsChartConfig": { "type": "object", "required": [ "displayType", "sourceId" ], "description": "Configuration for an event pattern mining tile. Clusters log or trace events by recurring message shapes.", "properties": { "displayType": { "type": "string", "enum": [ "event_patterns" ], "description": "Display type discriminator. Must be \"event_patterns\" for pattern mining tiles.", "example": "event_patterns" }, "sourceId": { "type": "string", "description": "ID of the data source to mine patterns from.", "example": "65f5e4a3b9e77c001a111111" }, "select": { "type": "string", "maxLength": 10000, "description": "Column or expression to mine patterns from. Leave empty to use the source default (Body for logs, SpanName for traces).", "default": "", "example": "Body" }, "where": { "type": "string", "maxLength": 10000, "description": "Filter condition for the pattern mining query (syntax depends on whereLanguage).", "default": "", "example": "level:error" }, "whereLanguage": { "$ref": "#/components/schemas/QueryLanguage", "description": "Query language for the where clause." } } }, "MarkdownChartConfig": { "type": "object", "required": [ "displayType" ], "description": "Configuration for a freeform Markdown text tile.", "properties": { "displayType": { "type": "string", "enum": [ "markdown" ], "description": "Display type discriminator. Must be \"markdown\" for markdown text tiles.", "example": "markdown" }, "markdown": { "type": "string", "maxLength": 50000, "description": "Markdown content to render inside the tile.", "example": "# Dashboard Title\n\nThis is a markdown widget." } } }, "RawSqlChartConfigBase": { "type": "object", "required": [ "configType", "connectionId", "sqlTemplate" ], "description": "Shared fields for Raw SQL chart configs. Set configType to \"sql\" and provide connectionId + sqlTemplate instead of sourceId + select.", "properties": { "configType": { "type": "string", "enum": [ "sql" ], "description": "Must be \"sql\" to use the Raw SQL chart config variant.", "example": "sql" }, "connectionId": { "type": "string", "description": "ID of the ClickHouse connection to execute the query against.", "example": "65f5e4a3b9e77c001a567890" }, "sqlTemplate": { "type": "string", "maxLength": 100000, "description": "SQL query template to execute. Supports HyperDX template variables.", "example": "SELECT count() FROM otel_logs WHERE timestamp > now() - INTERVAL 1 HOUR" }, "sourceId": { "type": "string", "description": "Optional ID of the data source associated with this Raw SQL chart. Used for applying dashboard filters.", "example": "65f5e4a3b9e77c001a567890" }, "numberFormat": { "$ref": "#/components/schemas/NumberFormat", "description": "Number formatting options for displayed values." } } }, "LineRawSqlChartConfig": { "description": "Raw SQL configuration for a line time-series chart.", "allOf": [ { "$ref": "#/components/schemas/RawSqlChartConfigBase" }, { "type": "object", "required": [ "displayType" ], "properties": { "displayType": { "type": "string", "enum": [ "line" ], "description": "Display as a line time-series chart.", "example": "line" }, "compareToPreviousPeriod": { "type": "boolean", "description": "Overlay the equivalent previous time period for comparison.", "default": false }, "fillNulls": { "type": "boolean", "description": "Fill missing time buckets with zero instead of leaving gaps.", "default": true }, "alignDateRangeToGranularity": { "type": "boolean", "description": "Expand date range boundaries to the query granularity interval.", "default": true }, "fitYAxisToData": { "type": "boolean", "description": "Set the y-axis lower bound to the minimum of the displayed data instead of zero, making small fluctuations between series easier to see.\n", "default": false } } } ] }, "BarRawSqlChartConfig": { "description": "Raw SQL configuration for a stacked-bar time-series chart.", "allOf": [ { "$ref": "#/components/schemas/RawSqlChartConfigBase" }, { "type": "object", "required": [ "displayType" ], "properties": { "displayType": { "type": "string", "enum": [ "stacked_bar" ], "description": "Display as a stacked-bar time-series chart.", "example": "stacked_bar" }, "fillNulls": { "type": "boolean", "description": "Fill missing time buckets with zero instead of leaving gaps.", "default": true }, "alignDateRangeToGranularity": { "type": "boolean", "description": "Expand date range boundaries to the query granularity interval.", "default": true } } } ] }, "TableRawSqlChartConfig": { "description": "Raw SQL configuration for a table chart.", "allOf": [ { "$ref": "#/components/schemas/RawSqlChartConfigBase" }, { "type": "object", "required": [ "displayType" ], "properties": { "displayType": { "type": "string", "enum": [ "table" ], "description": "Display as a table chart.", "example": "table" }, "onClick": { "$ref": "#/components/schemas/OnClick", "description": "Optional link-out configuration applied when a user clicks a row." } } } ] }, "NumberRawSqlChartConfig": { "description": "Raw SQL configuration for a single big-number chart.", "allOf": [ { "$ref": "#/components/schemas/RawSqlChartConfigBase" }, { "type": "object", "required": [ "displayType" ], "properties": { "displayType": { "type": "string", "enum": [ "number" ], "description": "Display as a single big-number chart.", "example": "number" }, "color": { "$ref": "#/components/schemas/ChartPaletteToken", "description": "Optional static color applied to the displayed number. Raw SQL number tiles do not support conditional colorRules.\n" } } } ] }, "PieRawSqlChartConfig": { "description": "Raw SQL configuration for a pie chart.", "allOf": [ { "$ref": "#/components/schemas/RawSqlChartConfigBase" }, { "type": "object", "required": [ "displayType" ], "properties": { "displayType": { "type": "string", "enum": [ "pie" ], "description": "Display as a pie chart.", "example": "pie" } } } ] }, "CategoricalBarRawSqlChartConfig": { "description": "Raw SQL configuration for a categorical bar chart.", "allOf": [ { "$ref": "#/components/schemas/RawSqlChartConfigBase" }, { "type": "object", "required": [ "displayType" ], "properties": { "displayType": { "type": "string", "enum": [ "bar" ], "description": "Display as a categorical bar chart.", "example": "bar" } } } ] }, "LineChartConfig": { "description": "Line chart. Omit configType for the builder variant (requires sourceId and select). Set configType to \"sql\" for the Raw SQL variant (requires connectionId and sqlTemplate).\n", "oneOf": [ { "$ref": "#/components/schemas/LineBuilderChartConfig" }, { "$ref": "#/components/schemas/LineRawSqlChartConfig" } ], "discriminator": { "propertyName": "configType", "mapping": { "sql": "#/components/schemas/LineRawSqlChartConfig" } } }, "BarChartConfig": { "description": "Stacked-bar chart. Omit configType for the builder variant (requires sourceId and select). Set configType to \"sql\" for the Raw SQL variant (requires connectionId and sqlTemplate).\n", "oneOf": [ { "$ref": "#/components/schemas/BarBuilderChartConfig" }, { "$ref": "#/components/schemas/BarRawSqlChartConfig" } ], "discriminator": { "propertyName": "configType", "mapping": { "sql": "#/components/schemas/BarRawSqlChartConfig" } } }, "OnClickFilterTemplate": { "type": "object", "description": "A templated filter applied to the link-out destination. The rendered template value is combined with the expression as `expression IN (...)` on the destination search or dashboard. Multiple templates sharing the same expression are merged into a single IN clause.\n", "required": [ "kind", "expression", "template" ], "properties": { "kind": { "type": "string", "enum": [ "expressionTemplate" ], "description": "Filter template kind. Currently only \"expressionTemplate\" is supported.", "example": "expressionTemplate" }, "expression": { "type": "string", "minLength": 1, "description": "The column/expression to filter the destination by (e.g. \"ServiceName\").", "example": "ServiceName" }, "template": { "type": "string", "minLength": 1, "description": "Value template rendered against the clicked row; supports row column variables in `{{column}}` form (e.g. `{{ServiceName}}`).\n", "example": "{{ServiceName}}" } } }, "OnClickTarget": { "description": "Identifies the source (for type=search) or dashboard (for type=dashboard) to link out to. Set mode to \"id\" to resolve a concrete ID, or \"template\" to resolve by rendered name at click time.\n", "oneOf": [ { "type": "object", "required": [ "mode", "id" ], "properties": { "mode": { "type": "string", "enum": [ "id" ], "description": "Target is a single dashboard or log/trace source", "example": "id" }, "id": { "type": "string", "description": "ID of the target source (for search) or dashboard (for dashboard).", "example": "65f5e4a3b9e77c001a567890" } } }, { "type": "object", "required": [ "mode", "template" ], "properties": { "mode": { "type": "string", "enum": [ "template" ], "description": "Target is matched by name against the template.", "example": "template" }, "template": { "type": "string", "minLength": 1, "description": "Name template rendered against the clicked row; supports `{{column}}` variables.\n", "example": "{{ServiceName}}" } } } ], "discriminator": { "propertyName": "mode" } }, "OnClickSearch": { "type": "object", "required": [ "type", "target" ], "description": "Link-out that navigates to the HyperDX search view.", "properties": { "type": { "type": "string", "enum": [ "search" ], "description": "OnClick variant discriminator. Must be \"search\" for search link-outs.", "example": "search" }, "target": { "$ref": "#/components/schemas/OnClickTarget", "description": "The source to navigate to." }, "whereTemplate": { "type": "string", "description": "Optional WHERE clause template applied to the destination search.", "example": "ServiceName = '{{ServiceName}}'" }, "whereLanguage": { "$ref": "#/components/schemas/QueryLanguage", "description": "Language of the rendered whereTemplate." }, "filters": { "type": "array", "description": "Optional dashboard filter templates rendered against the clicked row.", "items": { "$ref": "#/components/schemas/OnClickFilterTemplate" } } } }, "OnClickDashboard": { "type": "object", "required": [ "type", "target" ], "description": "Link-out that navigates to a HyperDX dashboard.", "properties": { "type": { "type": "string", "enum": [ "dashboard" ], "description": "OnClick variant discriminator. Must be \"dashboard\" for dashboard link-outs.", "example": "dashboard" }, "target": { "$ref": "#/components/schemas/OnClickTarget", "description": "The dashboard to navigate to." }, "whereTemplate": { "type": "string", "description": "Optional WHERE clause template applied to the destination dashboard.", "example": "ServiceName = '{{ServiceName}}'" }, "whereLanguage": { "$ref": "#/components/schemas/QueryLanguage", "description": "Language of the rendered whereTemplate." }, "filters": { "type": "array", "description": "Optional dashboard filter templates rendered against the clicked row.", "items": { "$ref": "#/components/schemas/OnClickFilterTemplate" } } } }, "OnClickExternal": { "type": "object", "required": [ "type", "urlTemplate" ], "description": "Link-out that navigates to an arbitrary external URL (e.g. a Grafana or Langfuse dashboard). The rendered URL must be an absolute http(s) URL.\n", "properties": { "type": { "type": "string", "enum": [ "external" ], "description": "OnClick variant discriminator. Must be \"external\" for external link-outs.", "example": "external" }, "urlTemplate": { "type": "string", "minLength": 1, "description": "Handlebars template rendered against the clicked row; supports `{{column}}` variables. The rendered value must be an absolute http(s) URL.\n", "example": "https://example.com/d/abc?var-service={{ServiceName}}" } } }, "OnClick": { "description": "Link-out configuration applied when a user clicks a row of a table tile. Only table tiles (builder or raw SQL) currently support onClick. When target.mode is \"id\", the referenced source (type=search) or dashboard (type=dashboard) must already exist for the team.\n", "oneOf": [ { "$ref": "#/components/schemas/OnClickSearch" }, { "$ref": "#/components/schemas/OnClickDashboard" }, { "$ref": "#/components/schemas/OnClickExternal" } ], "discriminator": { "propertyName": "type", "mapping": { "search": "#/components/schemas/OnClickSearch", "dashboard": "#/components/schemas/OnClickDashboard", "external": "#/components/schemas/OnClickExternal" } } }, "TableChartConfig": { "description": "Table chart. Omit configType for the builder variant (requires sourceId and select). Set configType to \"sql\" for the Raw SQL variant (requires connectionId and sqlTemplate).\n", "oneOf": [ { "$ref": "#/components/schemas/TableBuilderChartConfig" }, { "$ref": "#/components/schemas/TableRawSqlChartConfig" } ], "discriminator": { "propertyName": "configType", "mapping": { "sql": "#/components/schemas/TableRawSqlChartConfig" } } }, "NumberChartConfig": { "description": "Single big-number chart. Omit configType for the builder variant (requires sourceId and select). Set configType to \"sql\" for the Raw SQL variant (requires connectionId and sqlTemplate).\n", "oneOf": [ { "$ref": "#/components/schemas/NumberBuilderChartConfig" }, { "$ref": "#/components/schemas/NumberRawSqlChartConfig" } ], "discriminator": { "propertyName": "configType", "mapping": { "sql": "#/components/schemas/NumberRawSqlChartConfig" } } }, "PieChartConfig": { "description": "Pie chart. Omit configType for the builder variant (requires sourceId and select). Set configType to \"sql\" for the Raw SQL variant (requires connectionId and sqlTemplate).\n", "oneOf": [ { "$ref": "#/components/schemas/PieBuilderChartConfig" }, { "$ref": "#/components/schemas/PieRawSqlChartConfig" } ], "discriminator": { "propertyName": "configType", "mapping": { "sql": "#/components/schemas/PieRawSqlChartConfig" } } }, "CategoricalBarChartConfig": { "description": "Categorical bar chart (one bar per group value; not a time series). Omit configType for the builder variant (requires sourceId and select). Set configType to \"sql\" for the Raw SQL variant (requires connectionId and sqlTemplate).\n", "oneOf": [ { "$ref": "#/components/schemas/CategoricalBarBuilderChartConfig" }, { "$ref": "#/components/schemas/CategoricalBarRawSqlChartConfig" } ], "discriminator": { "propertyName": "configType", "mapping": { "sql": "#/components/schemas/CategoricalBarRawSqlChartConfig" } } }, "TileConfig": { "description": "Tile chart configuration. displayType is the primary discriminant and determines which variant group applies. For displayTypes that support both builder and Raw SQL modes (line, stacked_bar, table, number, pie, bar), configType is the secondary discriminant: omit it for the builder variant or set it to \"sql\" for the Raw SQL variant. The heatmap, search, event_patterns, and markdown displayTypes only have a builder variant.\n", "oneOf": [ { "$ref": "#/components/schemas/LineChartConfig" }, { "$ref": "#/components/schemas/BarChartConfig" }, { "$ref": "#/components/schemas/TableChartConfig" }, { "$ref": "#/components/schemas/NumberChartConfig" }, { "$ref": "#/components/schemas/PieChartConfig" }, { "$ref": "#/components/schemas/CategoricalBarChartConfig" }, { "$ref": "#/components/schemas/HeatmapChartConfig" }, { "$ref": "#/components/schemas/SearchChartConfig" }, { "$ref": "#/components/schemas/EventPatternsChartConfig" }, { "$ref": "#/components/schemas/MarkdownChartConfig" } ], "discriminator": { "propertyName": "displayType", "mapping": { "line": "#/components/schemas/LineChartConfig", "stacked_bar": "#/components/schemas/BarChartConfig", "table": "#/components/schemas/TableChartConfig", "number": "#/components/schemas/NumberChartConfig", "pie": "#/components/schemas/PieChartConfig", "bar": "#/components/schemas/CategoricalBarChartConfig", "heatmap": "#/components/schemas/HeatmapChartConfig", "search": "#/components/schemas/SearchChartConfig", "event_patterns": "#/components/schemas/EventPatternsChartConfig", "markdown": "#/components/schemas/MarkdownChartConfig" } } }, "DashboardContainerTab": { "type": "object", "description": "A single tab inside a dashboard container. Tiles join a tab via tabId.", "required": [ "id", "title" ], "properties": { "id": { "type": "string", "minLength": 1, "maxLength": 256, "description": "Unique identifier for the tab within its container.", "example": "errors" }, "title": { "type": "string", "minLength": 1, "maxLength": 256, "description": "Display title for the tab.", "example": "Errors" } } }, "DashboardContainer": { "type": "object", "description": "A grouping container for tiles on a dashboard. Tiles join a container via containerId.", "required": [ "id", "title", "collapsed" ], "properties": { "id": { "type": "string", "minLength": 1, "maxLength": 256, "description": "Unique identifier for the container within the dashboard.", "example": "service-health" }, "title": { "type": "string", "minLength": 1, "maxLength": 256, "description": "Display title for the container.", "example": "Service Health" }, "collapsed": { "type": "boolean", "description": "Persisted default collapse state. Per-viewer state lives in the URL.", "example": false }, "collapsible": { "type": "boolean", "description": "Whether the user can collapse the group.", "default": true, "example": true }, "bordered": { "type": "boolean", "description": "Whether to show a visual border around the group.", "default": true, "example": true }, "tabs": { "type": "array", "description": "Optional tabs. 2+ entries renders a tab bar; 0-1 entries renders a plain group header. Tiles join a tab via tabId.", "maxItems": 20, "items": { "$ref": "#/components/schemas/DashboardContainerTab" } } } }, "TileBase": { "type": "object", "description": "Common fields shared by tile input and output", "required": [ "name", "x", "y", "w", "h" ], "properties": { "name": { "type": "string", "description": "Display name for the tile", "example": "Error Rate" }, "x": { "type": "integer", "minimum": 0, "maximum": 23, "description": "Horizontal position in the grid (0-based)", "example": 0 }, "y": { "type": "integer", "minimum": 0, "description": "Vertical position in the grid (0-based)", "example": 0 }, "w": { "type": "integer", "minimum": 1, "maximum": 24, "description": "Width in grid units", "example": 6 }, "h": { "type": "integer", "minimum": 1, "description": "Height in grid units", "example": 3 }, "config": { "$ref": "#/components/schemas/TileConfig", "description": "Chart configuration for the tile. The displayType field determines which variant is used. Replaces the deprecated \"series\" and \"asRatio\" fields." }, "containerId": { "type": "string", "minLength": 1, "maxLength": 256, "description": "References a DashboardContainer by id. Tiles without containerId render in the default ungrouped area.", "example": "service-health" }, "tabId": { "type": "string", "minLength": 1, "maxLength": 256, "description": "References a tab inside the tile's container by id. Requires containerId to be set, and the container to declare a matching tab.", "example": "errors" } } }, "TileOutput": { "description": "Response format for dashboard tiles", "allOf": [ { "$ref": "#/components/schemas/TileBase" }, { "type": "object", "required": [ "id" ], "properties": { "id": { "type": "string", "maxLength": 36, "description": "Unique tile ID assigned by the server.", "example": "65f5e4a3b9e77c001a901234" } } } ] }, "TileInput": { "description": "Input / request format when creating or updating tiles. The id field is optional: on create it is ignored (the server always assigns a new ID); on update, a matching id is used to identify the existing tile to preserve. Tiles whose id does not match an existing tile are assigned a new generated ID.\n", "allOf": [ { "$ref": "#/components/schemas/TileBase" }, { "type": "object", "properties": { "id": { "type": "string", "maxLength": 36, "description": "Optional tile ID. Omit to generate a new ID.", "example": "65f5e4a3b9e77c001a901234" }, "asRatio": { "type": "boolean", "description": "Display two series as a ratio (series[0] / series[1]). Only applicable when providing \"series\". Deprecated in favor of \"config.asRatio\".", "example": false, "deprecated": true }, "series": { "type": "array", "minItems": 1, "description": "Data series to display in this tile (all must be the same type). Deprecated; use \"config\" instead.", "deprecated": true, "items": { "$ref": "#/components/schemas/DashboardChartSeries" } } } } ] }, "FilterInput": { "type": "object", "description": "Dashboard filter key that can be added to a dashboard", "required": [ "type", "name", "expression", "sourceId" ], "properties": { "type": { "type": "string", "enum": [ "QUERY_EXPRESSION" ], "description": "Filter type. Must be \"QUERY_EXPRESSION\".", "example": "QUERY_EXPRESSION" }, "name": { "type": "string", "minLength": 1, "description": "Display name for the dashboard filter key", "example": "Environment" }, "expression": { "type": "string", "minLength": 1, "description": "Key expression used when applying this dashboard filter key", "example": "environment" }, "sourceId": { "type": "string", "description": "Source ID this dashboard filter key applies to", "example": "65f5e4a3b9e77c001a111111" }, "sourceMetricType": { "type": "string", "enum": [ "sum", "gauge", "histogram", "summary", "exponential histogram" ], "description": "Metric type when source is metrics", "example": "gauge" }, "where": { "type": "string", "description": "Optional WHERE condition to scope which rows this filter key reads values from", "example": "ServiceName:api" }, "whereLanguage": { "type": "string", "enum": [ "sql", "lucene" ], "description": "Language of the where condition", "default": "sql", "example": "lucene" }, "appliesToSourceIds": { "type": "array", "items": { "type": "string" }, "description": "Optional list of source IDs this filter applies to. Omit or provide\nan empty array to apply the filter to ALL tiles regardless of source.\nA non-empty array restricts the filter to only tiles whose source ID\nis in the list; tiles using other sources are not affected by the\nselected filter value(s).\n", "example": [ "65f5e4a3b9e77c001a111111" ] } } }, "Filter": { "allOf": [ { "$ref": "#/components/schemas/FilterInput" }, { "type": "object", "required": [ "id" ], "properties": { "id": { "type": "string", "description": "Unique dashboard filter key ID" } } } ] }, "Dashboard": { "type": "object", "description": "Dashboard with tiles and configuration", "properties": { "id": { "type": "string", "description": "Dashboard ID", "example": "65f5e4a3b9e77c001a567890" }, "name": { "type": "string", "description": "Dashboard name", "maxLength": 1024, "example": "Service Overview" }, "tiles": { "type": "array", "description": "List of tiles/charts in the dashboard", "items": { "$ref": "#/components/schemas/TileOutput" } }, "tags": { "type": "array", "description": "Tags for organizing and filtering dashboards", "items": { "type": "string", "maxLength": 32 }, "maxItems": 50, "example": [ "production", "monitoring" ] }, "filters": { "type": "array", "description": "Dashboard filter keys added to the dashboard and applied to all tiles", "items": { "$ref": "#/components/schemas/Filter" } }, "savedQuery": { "type": "string", "nullable": true, "description": "Optional default dashboard query restored when loading the dashboard.", "example": "service.name = 'api'" }, "savedQueryLanguage": { "$ref": "#/components/schemas/QueryLanguage", "nullable": true, "description": "Query language used by savedQuery.", "default": "lucene", "example": "sql" }, "savedFilterValues": { "type": "array", "description": "Optional default dashboard filter values restored when loading the dashboard.", "items": { "$ref": "#/components/schemas/SavedFilterValue" } }, "containers": { "type": "array", "description": "Optional grouping containers. Each tile may join a container via tile.containerId, and a tab inside it via tile.tabId.", "maxItems": 50, "items": { "$ref": "#/components/schemas/DashboardContainer" } } } }, "CreateDashboardRequest": { "type": "object", "required": [ "name", "tiles" ], "properties": { "name": { "type": "string", "maxLength": 1024, "description": "Dashboard name.", "example": "New Dashboard" }, "tiles": { "type": "array", "description": "List of tiles/charts to include in the dashboard.", "maxItems": 500, "items": { "$ref": "#/components/schemas/TileInput" } }, "tags": { "type": "array", "description": "Tags for organizing and filtering dashboards.", "items": { "type": "string", "maxLength": 32 }, "maxItems": 50, "example": [ "development" ] }, "filters": { "type": "array", "description": "Dashboard filter keys to add to the dashboard and apply across all tiles", "items": { "$ref": "#/components/schemas/FilterInput" } }, "savedQuery": { "type": "string", "nullable": true, "description": "Optional default dashboard query to persist on the dashboard.", "example": "service.name = 'api'" }, "savedQueryLanguage": { "$ref": "#/components/schemas/QueryLanguage", "nullable": true, "description": "Query language used by savedQuery.", "default": "lucene", "example": "sql" }, "savedFilterValues": { "type": "array", "description": "Optional default dashboard filter values to persist on the dashboard.", "items": { "$ref": "#/components/schemas/SavedFilterValue" } }, "containers": { "type": "array", "description": "Optional grouping containers. Each tile may join a container via tile.containerId, and a tab inside it via tile.tabId.", "maxItems": 50, "items": { "$ref": "#/components/schemas/DashboardContainer" } } } }, "UpdateDashboardRequest": { "type": "object", "required": [ "name", "tiles" ], "properties": { "name": { "type": "string", "maxLength": 1024, "description": "Dashboard name.", "example": "Updated Dashboard Name" }, "tiles": { "type": "array", "maxItems": 500, "items": { "$ref": "#/components/schemas/TileInput" }, "description": "Full list of tiles for the dashboard. Existing tiles are matched by ID; tiles with an ID that does not match an existing tile will be assigned a new generated ID." }, "tags": { "type": "array", "description": "Tags for organizing and filtering dashboards.", "items": { "type": "string", "maxLength": 32 }, "maxItems": 50, "example": [ "production", "updated" ] }, "filters": { "type": "array", "description": "Dashboard filter keys on the dashboard, applied across all tiles", "items": { "$ref": "#/components/schemas/Filter" } }, "savedQuery": { "type": "string", "nullable": true, "description": "Optional default dashboard query to persist on the dashboard.", "example": "service.name = 'api'" }, "savedQueryLanguage": { "$ref": "#/components/schemas/QueryLanguage", "nullable": true, "description": "Query language used by savedQuery.", "default": "lucene", "example": "sql" }, "savedFilterValues": { "type": "array", "description": "Optional default dashboard filter values to persist on the dashboard.", "items": { "$ref": "#/components/schemas/SavedFilterValue" } }, "containers": { "type": "array", "description": "Optional grouping containers. Each tile may join a container via tile.containerId, and a tab inside it via tile.tabId.", "maxItems": 50, "items": { "$ref": "#/components/schemas/DashboardContainer" } } } }, "DashboardResponse": { "allOf": [ { "$ref": "#/components/schemas/Dashboard" } ] }, "DashboardResponseEnvelope": { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/DashboardResponse", "description": "The dashboard object." } } }, "DashboardsListResponse": { "type": "object", "properties": { "data": { "type": "array", "description": "List of dashboard objects.", "items": { "$ref": "#/components/schemas/DashboardResponse" } } } }, "SavedSearchFilter": { "type": "object", "required": [ "condition" ], "description": "A single pinned filter applied to the search. New or changed filters must use the SQL predicate form the UI produces so they render as a sidebar facet: ` IN ('', ...)` (or `NOT IN` / `BETWEEN`). Conditions not in this form are rejected on create, and on update unless they are echoed back unchanged from the stored saved search (so a read-modify-write of a legacy filter still succeeds). Note: existing saved searches created in the UI may also return a Lucene text filter (`type: lucene`) or a structured comparison (`type: sql_ast` with `operator`/`left`/`right`); reads return these stored shapes verbatim, and they are preserved on unchanged update.", "properties": { "type": { "type": "string", "enum": [ "sql" ], "default": "sql", "description": "Always `sql`. Only SQL predicate filters render in the sidebar.", "example": "sql" }, "condition": { "type": "string", "maxLength": 8192, "description": "SQL predicate applied to the search, in ` IN (...)` form.", "example": "ServiceName IN ('checkout', 'payments')" } } }, "SavedSearch": { "type": "object", "required": [ "id", "name", "sourceId" ], "properties": { "id": { "type": "string", "readOnly": true, "description": "Unique saved search ID. Server-generated.", "example": "507f1f77bcf86cd799439011" }, "name": { "type": "string", "description": "Display name for the saved search.", "example": "Production Errors" }, "sourceId": { "type": "string", "description": "ID of the source this saved search queries.", "example": "507f1f77bcf86cd799439012" }, "select": { "type": "string", "description": "Comma-separated list of column expressions to display. Empty uses the source default.", "example": "Timestamp, ServiceName, Body" }, "where": { "type": "string", "description": "Row filter expression. The language is controlled by whereLanguage.", "example": "SeverityText:ERROR" }, "whereLanguage": { "type": "string", "enum": [ "lucene", "sql" ], "description": "Language used for the where filter.", "example": "lucene" }, "orderBy": { "type": "string", "description": "ORDER BY expression. Empty uses the source default.", "example": "Timestamp DESC" }, "tags": { "type": "array", "maxItems": 50, "items": { "type": "string", "maxLength": 32 }, "description": "Tags used to organize saved searches.", "example": [ "production", "errors" ] }, "filters": { "type": "array", "maxItems": 100, "description": "Structured pinned filters applied to the search.", "items": { "$ref": "#/components/schemas/SavedSearchFilter" }, "example": [ { "type": "sql", "condition": "ServiceName IN ('checkout', 'payments')" } ] }, "teamId": { "type": "string", "readOnly": true, "description": "ID of the team that owns the saved search.", "example": "507f1f77bcf86cd799439013" }, "createdAt": { "type": "string", "format": "date-time", "readOnly": true, "description": "Creation timestamp.", "example": "2025-01-01T00:00:00.000Z" }, "updatedAt": { "type": "string", "format": "date-time", "readOnly": true, "description": "Last update timestamp.", "example": "2025-06-15T10:30:00.000Z" } } }, "SavedSearchInput": { "type": "object", "required": [ "name", "sourceId" ], "properties": { "name": { "type": "string", "maxLength": 1024, "description": "Display name for the saved search.", "example": "Production Errors" }, "sourceId": { "type": "string", "description": "ID of the source to query. Must belong to the team.", "example": "507f1f77bcf86cd799439012" }, "select": { "type": "string", "maxLength": 4096, "description": "Comma-separated list of column expressions to display. Empty uses the source default.", "example": "Timestamp, ServiceName, Body" }, "where": { "type": "string", "maxLength": 8192, "description": "Row filter expression. The language is controlled by whereLanguage.", "example": "SeverityText:ERROR" }, "whereLanguage": { "type": "string", "enum": [ "lucene", "sql" ], "default": "lucene", "description": "Language used for the where filter.", "example": "lucene" }, "orderBy": { "type": "string", "maxLength": 1024, "description": "ORDER BY expression. Empty uses the source default.", "example": "Timestamp DESC" }, "tags": { "type": "array", "maxItems": 50, "description": "Tags used to organize saved searches.", "items": { "type": "string", "maxLength": 32 }, "example": [ "production", "errors" ] }, "filters": { "type": "array", "maxItems": 100, "description": "Structured pinned filters applied to the search.", "items": { "$ref": "#/components/schemas/SavedSearchFilter" }, "example": [ { "type": "sql", "condition": "ServiceName IN ('checkout', 'payments')" } ] } } }, "SavedSearchesListResponse": { "type": "object", "required": [ "data", "meta" ], "properties": { "data": { "type": "array", "description": "List of saved search objects.", "items": { "$ref": "#/components/schemas/SavedSearch" } }, "meta": { "$ref": "#/components/schemas/PaginationMeta", "description": "Pagination metadata for this result page." } } }, "SavedSearchResponseEnvelope": { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/SavedSearch", "description": "The saved search object." } } }, "SearchRequest": { "type": "object", "required": [ "sourceId" ], "properties": { "sourceId": { "type": "string", "description": "Source ID to query. Call GET /api/v2/sources to list available sources.\nThe source determines the underlying ClickHouse table (e.g. otel.otel_logs,\notel.otel_traces) and its column schema.\n", "example": "69b46cb0d964ce2d0b9506a8" }, "startTime": { "type": "string", "format": "date-time", "description": "Start of the query window (ISO 8601). Defaults to 15 minutes before endTime. Must be before endTime.\n", "example": "2026-05-10T00:00:00Z" }, "endTime": { "type": "string", "format": "date-time", "description": "End of the query window (ISO 8601). Defaults to now.", "example": "2026-05-10T01:00:00Z" }, "where": { "type": "string", "maxLength": 8192, "default": "", "description": "Row filter expression. The language is controlled by whereLanguage.\n\nLucene examples (default):\n SeverityText:ERROR\n pipedream.pipeline_name:my-pipeline AND SeverityText:ERROR\n Body:timeout\n\nSQL examples (whereLanguage: \"sql\"):\n SeverityText = 'ERROR'\n `pipedream.pipeline_name` = 'my-pipeline'\n", "example": "SeverityText:ERROR" }, "whereLanguage": { "type": "string", "enum": [ "lucene", "sql" ], "example": "lucene", "default": "lucene", "description": "Language used for the where filter. Default is lucene." }, "select": { "type": "string", "maxLength": 4096, "default": "", "description": "Comma-separated list of ClickHouse column expressions to include in\neach result row. When omitted the source's default select expression\nis used.\n\nEach entry is a ClickHouse SQL expression executed under the team's\ndatabase user. Semicolons and subqueries (SELECT keyword) are\nrejected; use column references, map lookups, or function calls only.\n\nHyperDX rewrites known attribute column names to their materialized\nequivalents automatically; you can still pass the logical name.\n", "example": "Timestamp,SeverityText,Body,pipedream.pipeline_name" }, "orderBy": { "type": "string", "maxLength": 1024, "description": "ClickHouse ORDER BY expression. When omitted the source's default\nordering (typically timestamp DESC) is used.\n", "example": "Timestamp DESC" }, "maxResults": { "type": "integer", "minimum": 1, "maximum": 2000, "default": 100, "description": "Maximum number of rows to return. Default is 100, max is 2000." }, "offset": { "type": "integer", "minimum": 0, "maximum": 10000, "default": 0, "description": "Number of rows to skip (best-effort offset pagination). Default is\n0, max is 10000. Offset pagination is non-deterministic when\nmultiple rows share the same timestamp; for reliable deep paging\nfilter by the last Timestamp value returned in the previous page\ninstead of using a large offset.\n" } } }, "SearchRow": { "type": "object", "description": "A single result row. Keys correspond to the requested columns (or the source default columns when columns was omitted). Values are strings or numbers as returned by ClickHouse.\n", "additionalProperties": true }, "SearchResponse": { "type": "object", "properties": { "data": { "type": "array", "description": "Array of result rows. Each row is an object with keys corresponding to the requested columns.", "items": { "$ref": "#/components/schemas/SearchRow" } }, "rows": { "type": "integer", "description": "Number of rows in this response (not total matching rows)." } } }, "QuerySetting": { "type": "object", "required": [ "setting", "value" ], "properties": { "setting": { "type": "string", "description": "ClickHouse setting name", "example": "max_threads" }, "value": { "type": "string", "description": "Setting value", "example": "4" } } }, "SourceFrom": { "type": "object", "required": [ "databaseName", "tableName" ], "properties": { "databaseName": { "type": "string", "description": "ClickHouse database name", "example": "otel" }, "tableName": { "type": "string", "description": "ClickHouse table name", "example": "otel_logs" } } }, "MetricSourceFrom": { "type": "object", "required": [ "databaseName" ], "properties": { "databaseName": { "type": "string", "description": "ClickHouse database name", "example": "otel" }, "tableName": { "type": "string", "description": "ClickHouse table name", "nullable": true, "example": "otel_metrics_gauge" } } }, "MetricTables": { "type": "object", "description": "Mapping of metric data types to table names. At least one must be specified.", "properties": { "gauge": { "type": "string", "description": "Table containing gauge metrics data", "example": "otel_metrics_gauge" }, "histogram": { "type": "string", "description": "Table containing histogram metrics data", "example": "otel_metrics_histogram" }, "sum": { "type": "string", "description": "Table containing sum metrics data", "example": "otel_metrics_sum" }, "summary": { "type": "string", "description": "Table containing summary metrics data. Note - not yet fully supported by HyperDX", "example": "otel_metrics_summary" }, "exponential histogram": { "type": "string", "description": "Table containing exponential histogram metrics data. Note - not yet fully supported by HyperDX", "example": "otel_metrics_exponential_histogram" } } }, "HighlightedAttributeExpression": { "type": "object", "required": [ "sqlExpression" ], "properties": { "sqlExpression": { "type": "string", "description": "SQL expression for the attribute", "example": "SpanAttributes['http.status_code']" }, "luceneExpression": { "type": "string", "description": "An optional, Lucene version of the sqlExpression expression. If provided, it is used when searching for this attribute value.", "nullable": true, "example": "http.status_code" }, "alias": { "type": "string", "description": "Optional alias for the attribute", "nullable": true, "example": "HTTP Status Code" } } }, "AggregatedColumn": { "type": "object", "required": [ "mvColumn", "aggFn" ], "properties": { "sourceColumn": { "type": "string", "description": "Source column name", "nullable": true, "example": "Duration" }, "aggFn": { "type": "string", "description": "Aggregation function (e.g., count, sum, avg)", "example": "sum" }, "mvColumn": { "type": "string", "description": "Materialized view column name", "example": "sum__Duration" } } }, "MaterializedView": { "type": "object", "required": [ "databaseName", "tableName", "dimensionColumns", "minGranularity", "timestampColumn", "aggregatedColumns" ], "properties": { "databaseName": { "type": "string", "description": "Database name for the materialized view", "example": "otel" }, "tableName": { "type": "string", "description": "Table name for the materialized view", "example": "otel_logs_mv_5m" }, "dimensionColumns": { "type": "string", "description": "Columns which are not pre-aggregated in the materialized view and can be used for filtering and grouping.", "example": "ServiceName, SeverityText" }, "minGranularity": { "type": "string", "description": "The granularity of the timestamp column: a positive integer followed by a unit (s, m, h, d). Common values: 1s, 15s, 30s, 1m, 5m, 15m, 30m, 1h, 2h, 6h, 12h, 1d, 2d, 7d, 30d.", "pattern": "^\\d+(s|m|h|d)$", "example": "5m" }, "minDate": { "type": "string", "format": "date-time", "description": "(Optional) The earliest date and time for which the materialized view contains data. If not provided, then HyperDX will assume that the materialized view contains data for all dates for which the source table contains data.", "nullable": true, "example": "2025-01-01T00:00:00Z" }, "timestampColumn": { "type": "string", "description": "Timestamp column name", "example": "Timestamp" }, "aggregatedColumns": { "type": "array", "description": "Columns which are pre-aggregated by the materialized view", "items": { "$ref": "#/components/schemas/AggregatedColumn" } } } }, "LogSource": { "type": "object", "required": [ "name", "kind", "connection", "from", "defaultTableSelectExpression", "timestampValueExpression" ], "properties": { "id": { "type": "string", "readOnly": true, "description": "Unique source ID. Server-generated; ignored if sent in create/update requests.", "example": "507f1f77bcf86cd799439011" }, "name": { "type": "string", "description": "Display name for the source.", "example": "Logs" }, "section": { "type": "string", "maxLength": 256, "description": "Optional grouping label used to organize sources in the source selector. Sources that share a section value are displayed together.", "example": "Billing" }, "disabled": { "type": "boolean", "description": "When true, the source is hidden from source selectors in the UI. Defaults to false.", "nullable": true, "example": false }, "kind": { "type": "string", "enum": [ "log" ], "description": "Source kind discriminator. Must be \"log\" for log sources.", "example": "log" }, "connection": { "type": "string", "description": "ID of the ClickHouse connection used by this source.", "example": "507f1f77bcf86cd799439012" }, "from": { "$ref": "#/components/schemas/SourceFrom", "description": "Database and table location of the source data." }, "querySettings": { "type": "array", "description": "Optional ClickHouse query settings applied when querying this source.", "items": { "$ref": "#/components/schemas/QuerySetting" }, "nullable": true }, "defaultTableSelectExpression": { "type": "string", "description": "Default columns selected in search results (this can be customized per search later)", "example": "Timestamp, ServiceName, SeverityText, Body" }, "timestampValueExpression": { "type": "string", "description": "DateTime column or expression that is part of your table's primary key.", "example": "Timestamp" }, "serviceNameExpression": { "type": "string", "description": "Expression to extract the service name from log rows.", "nullable": true, "example": "ServiceName" }, "severityTextExpression": { "type": "string", "description": "Expression to extract the severity/log level text.", "nullable": true, "example": "SeverityText" }, "bodyExpression": { "type": "string", "description": "Expression to extract the log message body.", "nullable": true, "example": "Body" }, "eventAttributesExpression": { "type": "string", "description": "Expression to extract event-level attributes.", "nullable": true, "example": "LogAttributes" }, "resourceAttributesExpression": { "type": "string", "description": "Expression to extract resource-level attributes.", "nullable": true, "example": "ResourceAttributes" }, "displayedTimestampValueExpression": { "type": "string", "description": "This DateTime column is used to display and order search results.", "nullable": true, "example": "TimestampTime" }, "metricSourceId": { "type": "string", "description": "HyperDX Source for metrics associated with logs. Optional", "nullable": true, "example": "507f1f77bcf86cd799439013" }, "traceSourceId": { "type": "string", "description": "HyperDX Source for traces associated with logs. Optional", "nullable": true, "example": "507f1f77bcf86cd799439014" }, "traceIdExpression": { "type": "string", "description": "Expression to extract the trace ID for correlating logs with traces.", "nullable": true, "example": "TraceId" }, "spanIdExpression": { "type": "string", "description": "Expression to extract the span ID for correlating logs with traces.", "nullable": true, "example": "SpanId" }, "implicitColumnExpression": { "type": "string", "description": "Column used for full text search if no property is specified in a Lucene-based search. Typically the message body of a log.", "nullable": true, "example": "Body" }, "knownColumnsListExpression": { "type": "string", "description": "For Distributed table sources whose target tables have non-matching column sets. A list of columns supported across all target tables, used instead of SELECT * when fetching full row data. Leave blank to select all columns.", "nullable": true, "example": "Timestamp, Body, ServiceName" }, "useTextIndexForImplicitColumn": { "type": "string", "enum": [ "auto", "enabled", "disabled" ], "description": "Controls whether lucene rendering uses ClickHouse text indices via hasAllTokens() against the implicit column. \"auto\" detects a covering index at query time, \"enabled\" forces text index usage, \"disabled\" forces a LIKE/hasToken fallback.", "nullable": true, "example": "auto" }, "highlightedTraceAttributeExpressions": { "type": "array", "description": "Expressions defining trace-level attributes which are displayed in the trace view for the selected trace.", "items": { "$ref": "#/components/schemas/HighlightedAttributeExpression" }, "nullable": true }, "highlightedRowAttributeExpressions": { "type": "array", "description": "Expressions defining row-level attributes which are displayed in the row side panel for the selected row.", "items": { "$ref": "#/components/schemas/HighlightedAttributeExpression" }, "nullable": true }, "materializedViews": { "type": "array", "description": "Configure materialized views for query optimization. These pre-aggregated views can significantly improve query performance on aggregation queries.", "items": { "$ref": "#/components/schemas/MaterializedView" }, "nullable": true }, "metadataMaterializedViews": { "type": "object", "description": "Configure materialized views for fast field discovery and value autocomplete.", "nullable": true, "properties": { "keyRollupTable": { "type": "string", "description": "ClickHouse table name for the key rollup (field discovery).", "example": "otel_logs_key_rollup_15m" }, "kvRollupTable": { "type": "string", "description": "ClickHouse table name for the key-value rollup (value autocomplete).", "example": "otel_logs_kv_rollup_15m" }, "granularity": { "type": "string", "description": "The time granularity of the rollup tables.", "example": "15m" } } } } }, "TraceSource": { "type": "object", "required": [ "name", "kind", "connection", "from", "defaultTableSelectExpression", "timestampValueExpression", "durationExpression", "durationPrecision", "traceIdExpression", "spanIdExpression", "parentSpanIdExpression", "spanNameExpression", "spanKindExpression" ], "properties": { "id": { "type": "string", "readOnly": true, "description": "Unique source ID. Server-generated; ignored if sent in create/update requests.", "example": "507f1f77bcf86cd799439021" }, "name": { "type": "string", "description": "Display name for the source.", "example": "Traces" }, "section": { "type": "string", "maxLength": 256, "description": "Optional grouping label used to organize sources in the source selector. Sources that share a section value are displayed together.", "example": "Billing" }, "disabled": { "type": "boolean", "description": "When true, the source is hidden from source selectors in the UI. Defaults to false.", "nullable": true, "example": false }, "kind": { "type": "string", "enum": [ "trace" ], "description": "Source kind discriminator. Must be \"trace\" for trace sources.", "example": "trace" }, "connection": { "type": "string", "description": "ID of the ClickHouse connection used by this source.", "example": "507f1f77bcf86cd799439012" }, "from": { "$ref": "#/components/schemas/SourceFrom", "description": "Database and table location of the source data." }, "querySettings": { "type": "array", "description": "Optional ClickHouse query settings applied when querying this source.", "items": { "$ref": "#/components/schemas/QuerySetting" }, "nullable": true }, "defaultTableSelectExpression": { "type": "string", "description": "Default columns selected in search results (this can be customized per search later)", "example": "Timestamp, SpanName, ServiceName, Duration" }, "timestampValueExpression": { "type": "string", "description": "DateTime column or expression defines the start of the span", "example": "Timestamp" }, "durationExpression": { "type": "string", "description": "Expression to extract span duration.", "example": "Duration" }, "durationPrecision": { "type": "integer", "minimum": 0, "maximum": 9, "default": 3, "description": "Number of decimal digits in the duration value (e.g., 3 for milliseconds, 6 for microseconds, 9 for nanoseconds)." }, "traceIdExpression": { "type": "string", "description": "Expression to extract the trace ID.", "example": "TraceId" }, "spanIdExpression": { "type": "string", "description": "Expression to extract the span ID.", "example": "SpanId" }, "parentSpanIdExpression": { "type": "string", "description": "Expression to extract the parent span ID.", "example": "ParentSpanId" }, "spanNameExpression": { "type": "string", "description": "Expression to extract the span name.", "example": "SpanName" }, "spanKindExpression": { "type": "string", "description": "Expression to extract the span kind (e.g., client, server, internal).", "example": "SpanKind" }, "logSourceId": { "type": "string", "description": "HyperDX Source for logs associated with traces. Optional", "nullable": true, "example": "507f1f77bcf86cd799439011" }, "sessionSourceId": { "type": "string", "description": "HyperDX Source for sessions associated with traces. Optional", "nullable": true, "example": "507f1f77bcf86cd799439031" }, "metricSourceId": { "type": "string", "description": "HyperDX Source for metrics associated with traces. Optional", "nullable": true, "example": "507f1f77bcf86cd799439041" }, "statusCodeExpression": { "type": "string", "description": "Expression to extract the span status code.", "nullable": true, "example": "StatusCode" }, "statusMessageExpression": { "type": "string", "description": "Expression to extract the span status message.", "nullable": true, "example": "StatusMessage" }, "serviceNameExpression": { "type": "string", "description": "Expression to extract the service name from trace rows.", "nullable": true, "example": "ServiceName" }, "resourceAttributesExpression": { "type": "string", "description": "Expression to extract resource-level attributes.", "nullable": true, "example": "ResourceAttributes" }, "eventAttributesExpression": { "type": "string", "description": "Expression to extract event-level attributes.", "nullable": true, "example": "SpanAttributes" }, "spanEventsValueExpression": { "type": "string", "description": "Expression to extract span events. Used to capture events associated with spans. Expected to be Nested ( Timestamp DateTime64(9), Name LowCardinality(String), Attributes Map(LowCardinality(String), String)", "nullable": true, "example": "Events" }, "implicitColumnExpression": { "type": "string", "description": "Column used for full text search if no property is specified in a Lucene-based search. Typically the message body of a log.", "nullable": true, "example": "SpanName" }, "knownColumnsListExpression": { "type": "string", "description": "For Distributed table sources whose target tables have non-matching column sets. A list of columns supported across all target tables, used instead of SELECT * when fetching full row data. Leave blank to select all columns.", "nullable": true, "example": "Timestamp, Body, ServiceName" }, "useTextIndexForImplicitColumn": { "type": "string", "enum": [ "auto", "enabled", "disabled" ], "description": "Controls whether lucene rendering uses ClickHouse text indices via hasAllTokens() against the implicit column. \"auto\" detects a covering index at query time, \"enabled\" forces text index usage, \"disabled\" forces a LIKE/hasToken fallback.", "nullable": true, "example": "auto" }, "highlightedTraceAttributeExpressions": { "type": "array", "description": "Expressions defining trace-level attributes which are displayed in the trace view for the selected trace.", "items": { "$ref": "#/components/schemas/HighlightedAttributeExpression" }, "nullable": true }, "highlightedRowAttributeExpressions": { "type": "array", "description": "Expressions defining row-level attributes which are displayed in the row side panel for the selected row", "items": { "$ref": "#/components/schemas/HighlightedAttributeExpression" }, "nullable": true }, "materializedViews": { "type": "array", "description": "Configure materialized views for query optimization. These pre-aggregated views can significantly improve query performance on aggregation queries.", "items": { "$ref": "#/components/schemas/MaterializedView" }, "nullable": true }, "metadataMaterializedViews": { "type": "object", "description": "Configure materialized views for fast field discovery and value autocomplete.", "nullable": true, "properties": { "keyRollupTable": { "type": "string", "description": "ClickHouse table name for the key rollup (field discovery).", "example": "otel_traces_key_rollup_15m" }, "kvRollupTable": { "type": "string", "description": "ClickHouse table name for the key-value rollup (value autocomplete).", "example": "otel_traces_kv_rollup_15m" }, "granularity": { "type": "string", "description": "The time granularity of the rollup tables.", "example": "15m" } } } } }, "MetricSource": { "type": "object", "required": [ "name", "kind", "connection", "from", "metricTables", "timestampValueExpression", "resourceAttributesExpression" ], "properties": { "id": { "type": "string", "readOnly": true, "description": "Unique source ID. Server-generated; ignored if sent in create/update requests.", "example": "507f1f77bcf86cd799439041" }, "name": { "type": "string", "description": "Display name for the source.", "example": "Metrics" }, "section": { "type": "string", "maxLength": 256, "description": "Optional grouping label used to organize sources in the source selector. Sources that share a section value are displayed together.", "example": "Billing" }, "disabled": { "type": "boolean", "description": "When true, the source is hidden from source selectors in the UI. Defaults to false.", "nullable": true, "example": false }, "kind": { "type": "string", "enum": [ "metric" ], "description": "Source kind discriminator. Must be \"metric\" for metric sources.", "example": "metric" }, "connection": { "type": "string", "description": "ID of the ClickHouse connection used by this source.", "example": "507f1f77bcf86cd799439012" }, "from": { "$ref": "#/components/schemas/MetricSourceFrom", "description": "Database and optional table location of the metric source data." }, "querySettings": { "type": "array", "description": "Optional ClickHouse query settings applied when querying this source.", "items": { "$ref": "#/components/schemas/QuerySetting" }, "nullable": true }, "metricTables": { "$ref": "#/components/schemas/MetricTables", "description": "Mapping of metric data types to their respective table names." }, "timestampValueExpression": { "type": "string", "description": "DateTime column or expression that is part of your table's primary key.", "example": "TimeUnix" }, "resourceAttributesExpression": { "type": "string", "description": "Column containing resource attributes for metrics", "example": "ResourceAttributes" }, "logSourceId": { "type": "string", "description": "HyperDX Source for logs associated with metrics. Optional", "nullable": true, "example": "507f1f77bcf86cd799439011" } } }, "SessionSource": { "type": "object", "required": [ "name", "kind", "connection", "from", "traceSourceId" ], "properties": { "id": { "type": "string", "readOnly": true, "description": "Unique source ID. Server-generated; ignored if sent in create/update requests.", "example": "507f1f77bcf86cd799439031" }, "name": { "type": "string", "description": "Display name for the source.", "example": "Sessions" }, "section": { "type": "string", "maxLength": 256, "description": "Optional grouping label used to organize sources in the source selector. Sources that share a section value are displayed together.", "example": "Billing" }, "disabled": { "type": "boolean", "description": "When true, the source is hidden from source selectors in the UI. Defaults to false.", "nullable": true, "example": false }, "kind": { "type": "string", "enum": [ "session" ], "description": "Source kind discriminator. Must be \"session\" for session sources.", "example": "session" }, "connection": { "type": "string", "description": "ID of the ClickHouse connection used by this source.", "example": "507f1f77bcf86cd799439012" }, "from": { "$ref": "#/components/schemas/SourceFrom", "description": "Database and table location of the source data." }, "querySettings": { "type": "array", "description": "Optional ClickHouse query settings applied when querying this source.", "items": { "$ref": "#/components/schemas/QuerySetting" }, "nullable": true }, "timestampValueExpression": { "type": "string", "description": "DateTime column or expression that is part of your table's primary key.", "nullable": true, "example": "TimestampTime" }, "traceSourceId": { "type": "string", "description": "HyperDX Source for traces associated with sessions.", "example": "507f1f77bcf86cd799439021" } } }, "PromqlSource": { "type": "object", "description": "A source backed by a Prometheus-compatible endpoint, queried with PromQL. The referenced connection should be a Prometheus connection (isPrometheusEndpoint set to true).", "required": [ "name", "kind", "connection", "from", "timestampValueExpression" ], "properties": { "id": { "type": "string", "readOnly": true, "description": "Unique source ID. Server-generated; ignored if sent in create/update requests.", "example": "507f1f77bcf86cd799439051" }, "name": { "type": "string", "description": "Display name for the source.", "example": "Prometheus Metrics" }, "section": { "type": "string", "maxLength": 256, "description": "Optional grouping label used to organize sources in the source selector. Sources that share a section value are displayed together.", "example": "Billing" }, "disabled": { "type": "boolean", "description": "When true, the source is hidden from source selectors in the UI. Defaults to false.", "nullable": true, "example": false }, "kind": { "type": "string", "enum": [ "promql" ], "description": "Source kind discriminator. Must be \"promql\" for PromQL sources.", "example": "promql" }, "connection": { "type": "string", "description": "ID of the connection used by this source. Should reference a Prometheus-compatible connection.", "example": "507f1f77bcf86cd799439012" }, "from": { "$ref": "#/components/schemas/SourceFrom", "description": "Required by the API for all source kinds; not used when querying a Prometheus endpoint (empty strings are not accepted — use placeholder values such as \"default\")." }, "querySettings": { "type": "array", "description": "Optional ClickHouse query settings applied when querying this source.", "items": { "$ref": "#/components/schemas/QuerySetting" }, "nullable": true }, "timestampValueExpression": { "type": "string", "description": "Required by the API for all source kinds; not used when querying a Prometheus endpoint.", "example": "timestamp" } } }, "Source": { "oneOf": [ { "$ref": "#/components/schemas/LogSource" }, { "$ref": "#/components/schemas/TraceSource" }, { "$ref": "#/components/schemas/MetricSource" }, { "$ref": "#/components/schemas/SessionSource" }, { "$ref": "#/components/schemas/PromqlSource" } ], "discriminator": { "propertyName": "kind", "mapping": { "log": "#/components/schemas/LogSource", "trace": "#/components/schemas/TraceSource", "metric": "#/components/schemas/MetricSource", "session": "#/components/schemas/SessionSource", "promql": "#/components/schemas/PromqlSource" } } }, "SourcesListResponse": { "type": "object", "properties": { "data": { "type": "array", "description": "List of source objects.", "items": { "$ref": "#/components/schemas/Source" } } } }, "SourceResponseEnvelope": { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/Source", "description": "The source object." } } }, "SlackWebhook": { "type": "object", "required": [ "id", "name", "service", "updatedAt", "createdAt" ], "properties": { "id": { "type": "string", "description": "Webhook ID", "example": "507f1f77bcf86cd799439011" }, "name": { "type": "string", "description": "Webhook name", "example": "Production Alerts" }, "service": { "type": "string", "enum": [ "slack" ], "description": "Webhook service type", "example": "slack" }, "url": { "type": "string", "description": "Slack incoming webhook URL", "example": "https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX" }, "description": { "type": "string", "description": "Webhook description, shown in the UI", "example": "Sends critical alerts to the #incidents channel" }, "updatedAt": { "type": "string", "format": "date-time", "description": "Last update timestamp", "example": "2025-06-15T10:30:00.000Z" }, "createdAt": { "type": "string", "format": "date-time", "description": "Creation timestamp", "example": "2025-01-01T00:00:00.000Z" } } }, "IncidentIOWebhook": { "type": "object", "required": [ "id", "name", "service", "updatedAt", "createdAt" ], "properties": { "id": { "type": "string", "description": "Webhook ID", "example": "507f1f77bcf86cd799439012" }, "name": { "type": "string", "description": "Webhook name", "example": "Incident Response" }, "service": { "type": "string", "enum": [ "incidentio" ], "description": "Webhook service type", "example": "incidentio" }, "url": { "type": "string", "description": "incident.io alert event HTTP source URL", "example": "https://api.incident.io/v2/alert_events/http/abc123" }, "description": { "type": "string", "description": "Webhook description, shown in the UI", "example": "Routes alerts to incident.io for on-call escalation" }, "updatedAt": { "type": "string", "format": "date-time", "description": "Last update timestamp", "example": "2025-06-15T10:30:00.000Z" }, "createdAt": { "type": "string", "format": "date-time", "description": "Creation timestamp", "example": "2025-01-01T00:00:00.000Z" } } }, "GenericWebhook": { "type": "object", "required": [ "id", "name", "service", "updatedAt", "createdAt" ], "properties": { "id": { "type": "string", "description": "Webhook ID", "example": "507f1f77bcf86cd799439013" }, "name": { "type": "string", "description": "Webhook name", "example": "PagerDuty Integration" }, "service": { "type": "string", "enum": [ "generic" ], "description": "Webhook service type", "example": "generic" }, "url": { "type": "string", "description": "Webhook destination URL", "example": "https://example.com/webhooks/alerts" }, "description": { "type": "string", "description": "Webhook description, shown in the UI", "example": "Forwards alert payloads to an external monitoring service" }, "body": { "type": "string", "description": "Optional request body template", "example": "{\"alert\": \"{{title}}\", \"severity\": \"{{level}}\"}" }, "updatedAt": { "type": "string", "format": "date-time", "description": "Last update timestamp", "example": "2025-06-15T10:30:00.000Z" }, "createdAt": { "type": "string", "format": "date-time", "description": "Creation timestamp", "example": "2025-01-01T00:00:00.000Z" } } }, "Webhook": { "oneOf": [ { "$ref": "#/components/schemas/SlackWebhook" }, { "$ref": "#/components/schemas/IncidentIOWebhook" }, { "$ref": "#/components/schemas/GenericWebhook" } ], "discriminator": { "propertyName": "service", "mapping": { "slack": "#/components/schemas/SlackWebhook", "incidentio": "#/components/schemas/IncidentIOWebhook", "generic": "#/components/schemas/GenericWebhook" } } }, "PaginationMeta": { "type": "object", "required": [ "total", "limit", "offset" ], "properties": { "total": { "type": "integer", "description": "Total number of items matching the query, ignoring pagination.", "example": 142 }, "limit": { "type": "integer", "description": "Maximum number of items returned in this page.", "example": 50 }, "offset": { "type": "integer", "description": "Number of items skipped before this page.", "example": 100 } } }, "WebhooksListResponse": { "type": "object", "required": [ "data", "meta" ], "properties": { "data": { "type": "array", "description": "List of webhook objects.", "items": { "$ref": "#/components/schemas/Webhook" } }, "meta": { "$ref": "#/components/schemas/PaginationMeta", "description": "Pagination metadata for this result page." } } }, "WebhookInput": { "type": "object", "required": [ "name", "service", "url" ], "description": "Webhook create/update body. `body`, `headers`, and `queryParams`\nonly take effect for services that issue a templated HTTP request\n(`generic`, `incidentio`). The `slack` service posts a fixed payload\nto its incoming-webhook URL and ignores them, so supplying any of\nthese fields on a `slack` webhook is rejected. `headers` and\n`queryParams` are write-only — they are accepted here but never\nreturned by any read endpoint, so secrets such as auth tokens do\nnot leak. On\nupdate (PUT), omitted readable fields (`description`, `body`) are\ncleared, while omitted `headers`/`queryParams` are preserved —\nsend an explicit `{}` to clear them. Exception: if the destination\n(`url` or `service`) changes, omitted `headers`/`queryParams` are\ncleared rather than preserved, so stored secrets are never forwarded\nto a new destination; re-supply them for the new destination.\n", "properties": { "name": { "type": "string", "maxLength": 1024, "description": "Webhook name. Must be unique per service within the team.", "example": "Production Alerts" }, "service": { "type": "string", "enum": [ "slack", "incidentio", "generic" ], "description": "Webhook service type.", "example": "slack" }, "url": { "type": "string", "format": "uri", "maxLength": 2048, "description": "Webhook destination URL.", "example": "https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX" }, "description": { "type": "string", "maxLength": 2048, "description": "Webhook description, shown in the UI.", "example": "Sends critical alerts to the #incidents channel" }, "body": { "type": "string", "maxLength": 16384, "description": "Optional request body template. Only for generic/incidentio; rejected for slack.", "example": "{\"alert\": \"{{title}}\", \"severity\": \"{{level}}\"}" }, "headers": { "type": "object", "maxProperties": 100, "description": "Write-only. Custom HTTP headers sent with the webhook request. Never returned on read. Only for generic/incidentio; rejected for slack. Each value is capped at 4096 characters.", "additionalProperties": { "type": "string", "maxLength": 4096 }, "example": { "Authorization": "Bearer secret-token" } }, "queryParams": { "type": "object", "maxProperties": 100, "description": "Write-only. Query parameters appended to the webhook URL. Never returned on read. Only for generic/incidentio; rejected for slack. Each value is capped at 4096 characters.", "additionalProperties": { "type": "string", "maxLength": 4096 } } } }, "WebhookResponseEnvelope": { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/Webhook", "description": "The webhook object." } } } } }, "security": [ { "BearerAuth": [] } ], "paths": { "/api/v2/alerts/{id}": { "get": { "summary": "Get Alert", "description": "Retrieves a specific alert by ID", "operationId": "getAlert", "tags": [ "Alerts" ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "description": "Alert ID", "example": "65f5e4a3b9e77c001a123456" } ], "responses": { "200": { "description": "Successfully retrieved alert", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AlertResponseEnvelope" }, "examples": { "alertResponse": { "summary": "Single alert response", "value": { "data": { "id": "65f5e4a3b9e77c001a123456", "threshold": 80, "interval": "5m", "thresholdType": "above", "source": "tile", "state": "ALERT", "channel": { "type": "webhook", "webhookId": "65f5e4a3b9e77c001a789012" }, "teamId": "65f5e4a3b9e77c001a345678", "tileId": "65f5e4a3b9e77c001a901234", "dashboardId": "65f5e4a3b9e77c001a567890", "numConsecutiveWindows": 3, "createdAt": "2023-03-15T10:20:30.000Z", "updatedAt": "2023-03-15T14:25:10.000Z" } } } } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Alert not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "put": { "summary": "Update Alert", "description": "Updates an existing alert", "operationId": "updateAlert", "tags": [ "Alerts" ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "description": "Alert ID", "example": "65f5e4a3b9e77c001a123456" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateAlertRequest" }, "examples": { "updateAlert": { "summary": "Update alert properties", "value": { "threshold": 500, "interval": "1h", "thresholdType": "above", "source": "tile", "dashboardId": "65f5e4a3b9e77c001a567890", "tileId": "65f5e4a3b9e77c001a901234", "channel": { "type": "webhook", "webhookId": "65f5e4a3b9e77c001a789012" }, "name": "Updated Alert Name", "message": "Updated threshold and interval" } } } } } }, "responses": { "200": { "description": "Successfully updated alert", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AlertResponseEnvelope" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Alert not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Server error or validation failure", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "delete": { "summary": "Delete Alert", "description": "Deletes an alert", "operationId": "deleteAlert", "tags": [ "Alerts" ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "description": "Alert ID", "example": "65f5e4a3b9e77c001a123456" } ], "responses": { "200": { "description": "Successfully deleted alert", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EmptyResponse" }, "example": {} } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Alert not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/api/v2/alerts": { "get": { "summary": "List Alerts", "description": "Retrieves alerts for the authenticated team (paginated). Results are capped at `limit` (default and maximum 1000). When more records exist than are returned, `meta.total` exceeds `data.length`; clients with large collections must page with `limit`/`offset` to retrieve them all.", "operationId": "listAlerts", "tags": [ "Alerts" ], "parameters": [ { "name": "limit", "in": "query", "required": false, "schema": { "type": "integer", "minimum": 1, "maximum": 1000, "default": 1000 }, "description": "Maximum number of alerts to return." }, { "name": "offset", "in": "query", "required": false, "schema": { "type": "integer", "minimum": 0, "default": 0 }, "description": "Number of alerts to skip before returning results." } ], "responses": { "200": { "description": "Successfully retrieved alerts", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AlertsListResponse" }, "examples": { "alertsList": { "summary": "List of alerts", "value": { "data": [ { "id": "65f5e4a3b9e77c001a123456", "threshold": 100, "interval": "15m", "thresholdType": "above", "source": "tile", "state": "OK", "channel": { "type": "webhook", "webhookId": "65f5e4a3b9e77c001a789012" }, "teamId": "65f5e4a3b9e77c001a345678", "tileId": "65f5e4a3b9e77c001a901234", "dashboardId": "65f5e4a3b9e77c001a567890", "createdAt": "2023-01-01T00:00:00.000Z", "updatedAt": "2023-01-01T00:00:00.000Z" } ], "meta": { "total": 1, "limit": 1000, "offset": 0 } } } } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "message": "Unauthorized access. API key is missing or invalid." } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "post": { "summary": "Create Alert", "description": "Creates a new alert", "operationId": "createAlert", "tags": [ "Alerts" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateAlertRequest" }, "examples": { "tileAlert": { "summary": "Create a tile-based alert", "value": { "dashboardId": "65f5e4a3b9e77c001a567890", "tileId": "65f5e4a3b9e77c001a901234", "threshold": 100, "interval": "1h", "source": "tile", "thresholdType": "above", "channel": { "type": "webhook", "webhookId": "65f5e4a3b9e77c001a789012" }, "name": "Error Spike Alert", "message": "Error rate has exceeded 100 in the last hour", "numConsecutiveWindows": 3 } } } } } }, "responses": { "200": { "description": "Successfully created alert", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AlertResponseEnvelope" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Server error or validation failure", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/api/v2/charts/series": { "post": { "summary": "Query Chart Series Data", "description": "Retrieves time series data based on configured series parameters", "operationId": "queryChartSeries", "tags": [ "Charts" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SeriesQueryRequest" }, "examples": { "basicTimeSeries": { "summary": "Basic time series query", "value": { "startTime": 1647014400000, "endTime": 1647100800000, "granularity": "1h", "series": [ { "sourceId": "65f5e4a3b9e77c001a123456", "aggFn": "count", "where": "SeverityText:error", "groupBy": [] } ] } }, "multiSeriesWithGroupBy": { "summary": "Multiple series with group by", "value": { "startTime": 1647014400000, "endTime": 1647100800000, "granularity": "15m", "series": [ { "sourceId": "65f5e4a3b9e77c001a123456", "aggFn": "count", "where": "SeverityText:error", "groupBy": [ "service" ] }, { "sourceId": "65f5e4a3b9e77c001a123456", "aggFn": "avg", "field": "duration", "where": "SeverityText:error", "groupBy": [ "service" ] } ] } }, "multiSourceSeries": { "summary": "Series from multiple sources", "value": { "startTime": 1647014400000, "endTime": 1647100800000, "granularity": "5m", "series": [ { "sourceId": "65f5e4a3b9e77c001a123456", "aggFn": "count", "where": "SeverityText:error", "groupBy": [] }, { "sourceId": "65f5e4a3b9e77c001a789012", "aggFn": "avg", "metricName": "http_requests_total", "metricDataType": "gauge", "where": "service:api", "groupBy": [] } ] } }, "metricSeries": { "summary": "Metric data series", "value": { "startTime": 1647014400000, "endTime": 1647100800000, "granularity": "5m", "series": [ { "sourceId": "65f5e4a3b9e77c001a789012", "aggFn": "avg", "metricName": "http_requests_total", "metricDataType": "gauge", "where": "service:api", "groupBy": [] } ] } } } } } }, "responses": { "200": { "description": "Successfully retrieved time series data", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SeriesResponse" }, "examples": { "timeSeriesData": { "summary": "Time series data points", "value": { "data": [ { "ts_bucket": 1647014400000, "series_0.data": 42 }, { "ts_bucket": 1647018000000, "series_0.data": 37 }, { "ts_bucket": 1647021600000, "series_0.data": 53 } ] } }, "groupedTimeSeriesData": { "summary": "Grouped time series data", "value": { "data": [ { "ts_bucket": 1647014400000, "series_0.data": 15, "group": [ "api" ] }, { "ts_bucket": 1647014400000, "series_0.data": 8, "group": [ "frontend" ] }, { "ts_bucket": 1647018000000, "series_0.data": 22, "group": [ "api" ] } ] } } } } } }, "400": { "description": "Invalid request parameters", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } }, "examples": { "invalidParams": { "value": { "error": "All series must have the same groupBy fields" } }, "invalidTimestamp": { "value": { "error": "Timestamp must be in milliseconds" } } } } } }, "403": { "description": "Unauthorized", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } }, "example": { "error": "Team context missing" } } } }, "404": { "description": "Source not found", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } }, "example": { "error": "Source not found" } } } }, "500": { "description": "Server error", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } }, "example": { "error": "Internal server error" } } } } } } }, "/api/v2/connections": { "get": { "summary": "List Connections", "description": "Retrieves a list of all ClickHouse connections for the authenticated team. Passwords are never returned.", "operationId": "listConnections", "tags": [ "Connections" ], "responses": { "200": { "description": "Successfully retrieved connections", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ConnectionsListResponse" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "message": "Unauthorized access. API key is missing or invalid." } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "post": { "summary": "Create Connection", "description": "Creates a new ClickHouse connection", "operationId": "createConnection", "tags": [ "Connections" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateConnectionRequest" } } } }, "responses": { "200": { "description": "Successfully created connection", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ConnectionResponseEnvelope" } } } }, "400": { "description": "Bad request", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "message": "Body validation failed: name: Required" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "message": "Unauthorized access. API key is missing or invalid." } } } } } } }, "/api/v2/connections/{id}": { "get": { "summary": "Get Connection", "description": "Retrieves a specific ClickHouse connection by ID. Passwords are never returned.", "operationId": "getConnection", "tags": [ "Connections" ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "description": "Connection ID", "example": "507f1f77bcf86cd799439012" } ], "responses": { "200": { "description": "Successfully retrieved connection", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ConnectionResponseEnvelope" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "message": "Unauthorized access. API key is missing or invalid." } } } }, "404": { "description": "Connection not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "message": "Connection not found" } } } } } }, "put": { "summary": "Update Connection", "description": "Updates an existing ClickHouse connection.\n\nField semantics: if `password` is omitted or empty the existing\npassword is kept. `hyperdxSettingPrefix` is cleared when set to null\nor an empty string, and `prometheusEndpoint` is cleared when set to\nnull; both are kept unchanged when omitted.\n", "operationId": "updateConnection", "tags": [ "Connections" ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "description": "Connection ID", "example": "507f1f77bcf86cd799439012" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateConnectionRequest" } } } }, "responses": { "200": { "description": "Successfully updated connection", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ConnectionResponseEnvelope" } } } }, "400": { "description": "Bad request", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "message": "Body validation failed: host: Required" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "message": "Unauthorized access. API key is missing or invalid." } } } }, "404": { "description": "Connection not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "message": "Connection not found" } } } } } }, "delete": { "summary": "Delete Connection", "description": "Deletes a ClickHouse connection", "operationId": "deleteConnection", "tags": [ "Connections" ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "description": "Connection ID", "example": "507f1f77bcf86cd799439012" } ], "responses": { "200": { "description": "Successfully deleted connection", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EmptyResponse" }, "example": {} } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "message": "Unauthorized access. API key is missing or invalid." } } } }, "404": { "description": "Connection not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "message": "Connection not found" } } } } } } }, "/api/v2/dashboards": { "get": { "summary": "List Dashboards", "description": "Retrieves a list of all dashboards for the authenticated team", "operationId": "listDashboards", "tags": [ "Dashboards" ], "responses": { "200": { "description": "Successfully retrieved dashboards", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DashboardsListResponse" }, "examples": { "dashboards": { "summary": "Dashboards list response", "value": { "data": [ { "id": "65f5e4a3b9e77c001a567890", "name": "Infrastructure Monitoring", "tiles": [ { "id": "65f5e4a3b9e77c001a901234", "name": "Server CPU", "x": 0, "y": 0, "w": 6, "h": 3, "config": { "displayType": "line", "sourceId": "65f5e4a3b9e77c001a111111", "select": [ { "aggFn": "avg", "valueExpression": "cpu.usage", "where": "host:server-01" } ] } } ], "tags": [ "infrastructure", "monitoring" ], "filters": [ { "id": "65f5e4a3b9e77c001a301001", "type": "QUERY_EXPRESSION", "name": "Environment", "expression": "environment", "sourceId": "65f5e4a3b9e77c001a111111" } ] }, { "id": "65f5e4a3b9e77c001a567891", "name": "API Monitoring", "tiles": [ { "id": "65f5e4a3b9e77c001a901235", "name": "API Errors", "x": 0, "y": 0, "w": 6, "h": 3, "config": { "displayType": "table", "sourceId": "65f5e4a3b9e77c001a111112", "select": [ { "aggFn": "count", "where": "level:error" } ], "groupBy": "service", "orderBy": "count DESC" } } ], "tags": [ "api", "monitoring" ], "filters": [ { "id": "65f5e4a3b9e77c001a301002", "type": "QUERY_EXPRESSION", "name": "Service", "expression": "service_name", "sourceId": "65f5e4a3b9e77c001a111112" } ] } ] } } } } } }, "401": { "description": "Unauthorized" } } }, "post": { "summary": "Create Dashboard", "description": "Creates a new dashboard", "operationId": "createDashboard", "tags": [ "Dashboards" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateDashboardRequest" }, "examples": { "simpleTimeSeriesDashboard": { "summary": "Dashboard with a line chart", "value": { "name": "API Monitoring Dashboard", "tiles": [ { "name": "API Request Volume", "x": 0, "y": 0, "w": 6, "h": 3, "config": { "displayType": "line", "sourceId": "65f5e4a3b9e77c001a111111", "select": [ { "aggFn": "count", "where": "service:api" } ] } } ], "tags": [ "api", "monitoring" ], "filters": [ { "type": "QUERY_EXPRESSION", "name": "Environment", "expression": "environment", "sourceId": "65f5e4a3b9e77c001a111111" } ] } }, "complexDashboard": { "summary": "Dashboard with multiple chart types", "value": { "name": "Service Health Overview", "tiles": [ { "name": "Request Count", "x": 0, "y": 0, "w": 6, "h": 3, "config": { "displayType": "line", "sourceId": "65f5e4a3b9e77c001a111111", "select": [ { "aggFn": "count", "where": "service:backend" } ] } }, { "name": "Error Distribution", "x": 6, "y": 0, "w": 6, "h": 3, "config": { "displayType": "table", "sourceId": "65f5e4a3b9e77c001a111111", "select": [ { "aggFn": "count", "where": "level:error" } ], "groupBy": "errorType", "orderBy": "count DESC" } } ], "tags": [ "service-health", "production" ], "filters": [ { "type": "QUERY_EXPRESSION", "name": "Service", "expression": "service_name", "sourceId": "65f5e4a3b9e77c001a111111" } ] } } } } } }, "responses": { "200": { "description": "Successfully created dashboard", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DashboardResponseEnvelope" }, "examples": { "createdDashboard": { "summary": "Created dashboard response", "value": { "data": { "id": "65f5e4a3b9e77c001a567890", "name": "API Monitoring Dashboard", "tiles": [ { "id": "65f5e4a3b9e77c001a901234", "name": "API Request Volume", "x": 0, "y": 0, "w": 6, "h": 3, "config": { "displayType": "line", "sourceId": "65f5e4a3b9e77c001a111111", "select": [ { "aggFn": "count", "where": "service:api" } ] } } ], "tags": [ "api", "monitoring" ], "filters": [ { "id": "65f5e4a3b9e77c001a301004", "type": "QUERY_EXPRESSION", "name": "Environment", "expression": "environment", "sourceId": "65f5e4a3b9e77c001a111111" } ] } } } } } } }, "400": { "description": "Bad request", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "message": "Could not find the following source IDs: 68fa86308aa879b977aa6af6" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "message": "Unauthorized access. API key is missing or invalid." } } } }, "500": { "description": "Server error or validation failure", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "message": "Dashboard validation failed: name is required" } } } } } } }, "/api/v2/dashboards/{id}": { "get": { "summary": "Get Dashboard", "description": "Retrieves a specific dashboard by ID", "operationId": "getDashboard", "tags": [ "Dashboards" ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "description": "Dashboard ID", "example": "65f5e4a3b9e77c001a567890" } ], "responses": { "200": { "description": "Successfully retrieved dashboard", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DashboardResponseEnvelope" }, "examples": { "dashboard": { "summary": "Single dashboard response", "value": { "data": { "id": "65f5e4a3b9e77c001a567890", "name": "Infrastructure Monitoring", "tiles": [ { "id": "65f5e4a3b9e77c001a901234", "name": "Server CPU", "x": 0, "y": 0, "w": 6, "h": 3, "config": { "displayType": "line", "sourceId": "65f5e4a3b9e77c001a111111", "select": [ { "aggFn": "avg", "valueExpression": "cpu.usage", "where": "host:server-01" } ] } }, { "id": "65f5e4a3b9e77c001a901235", "name": "Memory Usage", "x": 6, "y": 0, "w": 6, "h": 3, "config": { "displayType": "line", "sourceId": "65f5e4a3b9e77c001a111111", "select": [ { "aggFn": "avg", "valueExpression": "memory.usage", "where": "host:server-01" } ] } } ], "tags": [ "infrastructure", "monitoring" ], "filters": [ { "id": "65f5e4a3b9e77c001a301003", "type": "QUERY_EXPRESSION", "name": "Environment", "expression": "environment", "sourceId": "65f5e4a3b9e77c001a111111" } ] } } } } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "message": "Unauthorized access. API key is missing or invalid." } } } }, "404": { "description": "Dashboard not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "message": "Dashboard not found" } } } } } }, "put": { "summary": "Update Dashboard", "description": "Updates an existing dashboard.\n\n**Concurrency:** This endpoint does not support optimistic\nconcurrency control. Concurrent PUT requests for the same\ndashboard may silently overwrite each other, which can leave\norphan tile-to-container references on layout-shape edits.\nClients should serialize edits to a given dashboard.\n", "operationId": "updateDashboard", "tags": [ "Dashboards" ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "description": "Dashboard ID", "example": "65f5e4a3b9e77c001a567890" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateDashboardRequest" }, "examples": { "updateDashboard": { "summary": "Update dashboard properties and tiles", "value": { "name": "Updated Dashboard Name", "tiles": [ { "id": "65f5e4a3b9e77c001a901234", "name": "Updated Line Chart", "x": 0, "y": 0, "w": 6, "h": 3, "config": { "displayType": "line", "sourceId": "65f5e4a3b9e77c001a111111", "select": [ { "aggFn": "count", "where": "level:error" } ] } }, { "id": "new-tile-123", "name": "New Number Chart", "x": 6, "y": 0, "w": 6, "h": 3, "config": { "displayType": "number", "sourceId": "65f5e4a3b9e77c001a111111", "select": [ { "aggFn": "count", "where": "level:info" } ] } } ], "tags": [ "production", "updated" ], "filters": [ { "id": "65f5e4a3b9e77c001a301005", "type": "QUERY_EXPRESSION", "name": "Environment", "expression": "environment", "sourceId": "65f5e4a3b9e77c001a111111" } ] } } } } } }, "responses": { "200": { "description": "Successfully updated dashboard", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DashboardResponseEnvelope" }, "examples": { "updatedDashboard": { "summary": "Updated dashboard response", "value": { "data": { "id": "65f5e4a3b9e77c001a567890", "name": "Updated Dashboard Name", "tiles": [ { "id": "65f5e4a3b9e77c001a901234", "name": "Updated Line Chart", "x": 0, "y": 0, "w": 6, "h": 3, "config": { "displayType": "line", "sourceId": "65f5e4a3b9e77c001a111111", "select": [ { "aggFn": "count", "where": "level:error" } ] } }, { "id": "new-tile-123", "name": "New Number Chart", "x": 6, "y": 0, "w": 6, "h": 3, "config": { "displayType": "number", "sourceId": "65f5e4a3b9e77c001a111111", "select": [ { "aggFn": "count", "where": "level:info" } ] } } ], "tags": [ "production", "updated" ], "filters": [ { "id": "65f5e4a3b9e77c001a301005", "type": "QUERY_EXPRESSION", "name": "Environment", "expression": "environment", "sourceId": "65f5e4a3b9e77c001a111111" } ] } } } } } } }, "400": { "description": "Bad request", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "message": "Could not find the following source IDs: 68fa86308aa879b977aa6af6" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "message": "Unauthorized access. API key is missing or invalid." } } } }, "404": { "description": "Dashboard not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "message": "Dashboard not found" } } } }, "500": { "description": "Server error or validation failure", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "message": "Invalid dashboard configuration" } } } } } }, "delete": { "summary": "Delete Dashboard", "description": "Deletes a dashboard", "operationId": "deleteDashboard", "tags": [ "Dashboards" ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "description": "Dashboard ID", "example": "65f5e4a3b9e77c001a567890" } ], "responses": { "200": { "description": "Successfully deleted dashboard", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EmptyResponse" }, "example": {} } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "message": "Unauthorized access. API key is missing or invalid." } } } }, "404": { "description": "Dashboard not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "message": "Dashboard not found" } } } } } } }, "/api/v2/dashboards/validate": { "post": { "summary": "Validate Dashboard", "description": "Validates a dashboard body against the same schema and tile rules used\nby POST /api/v2/dashboards. The dashboard is **never persisted**. Use\nthis endpoint at plan time (e.g. from a Terraform provider) to check\nthat a dashboard configuration is valid before applying it.\n", "operationId": "validateDashboard", "tags": [ "Dashboards" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateDashboardRequest" } } } }, "responses": { "200": { "description": "Validation result. HTTP 200 is always returned for valid **and**\ninvalid bodies — a non-200 response means the request itself\nfailed (auth, server error, etc.).\n", "content": { "application/json": { "schema": { "type": "object", "required": [ "valid", "errors", "normalized" ], "properties": { "valid": { "type": "boolean", "description": "True when the body passes all validation rules." }, "errors": { "type": "array", "description": "Validation errors. Empty when valid is true.", "items": { "type": "object", "required": [ "path", "message" ], "properties": { "path": { "type": "string", "description": "Dot-separated field path, or empty string for top-level errors." }, "message": { "type": "string", "description": "Human-readable error description." } } } }, "normalized": { "type": "object", "nullable": true, "description": "The parsed dashboard body with defaults applied (no\npersistence, so no server-assigned tile IDs). Populated\nwhen valid is true, null when valid is false.\n" } } }, "examples": { "valid": { "summary": "Valid dashboard body", "value": { "valid": true, "errors": [], "normalized": { "name": "My Dashboard", "tiles": [] } } }, "invalid": { "summary": "Invalid dashboard body", "value": { "valid": false, "errors": [ { "path": "name", "message": "Required" } ], "normalized": null } } } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "message": "Unauthorized access. API key is missing or invalid." } } } } } } }, "/api/v2/saved-searches": { "get": { "summary": "List Saved Searches", "description": "Retrieves saved searches for the authenticated team (paginated). Results are capped at `limit` (default and maximum 1000). When more records exist than are returned, `meta.total` exceeds `data.length`; clients with large collections must page with `limit`/`offset` to retrieve them all.", "operationId": "listSavedSearches", "tags": [ "Saved Searches" ], "parameters": [ { "name": "limit", "in": "query", "required": false, "schema": { "type": "integer", "minimum": 1, "maximum": 1000, "default": 1000 }, "description": "Maximum number of saved searches to return." }, { "name": "offset", "in": "query", "required": false, "schema": { "type": "integer", "minimum": 0, "default": 0 }, "description": "Number of saved searches to skip before returning results." } ], "responses": { "200": { "description": "Successfully retrieved saved searches", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SavedSearchesListResponse" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "post": { "summary": "Create Saved Search", "description": "Creates a new saved search.", "operationId": "createSavedSearch", "tags": [ "Saved Searches" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SavedSearchInput" } } } }, "responses": { "200": { "description": "Successfully created saved search", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SavedSearchResponseEnvelope" } } } }, "400": { "description": "Bad request", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/api/v2/saved-searches/{id}": { "get": { "summary": "Get Saved Search", "description": "Retrieves a specific saved search by ID.", "operationId": "getSavedSearch", "tags": [ "Saved Searches" ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "description": "Saved search ID", "example": "507f1f77bcf86cd799439011" } ], "responses": { "200": { "description": "Successfully retrieved saved search", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SavedSearchResponseEnvelope" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Saved search not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "put": { "summary": "Update Saved Search", "description": "Updates an existing saved search. This is a full replace: send the\nfull object. Every optional field (`select`, `where`, `whereLanguage`,\n`orderBy`, `tags`, `filters`) is always written and falls back to its\ndefault when omitted, so omitting a field resets it rather than\npreserving the stored value.\n", "operationId": "updateSavedSearch", "tags": [ "Saved Searches" ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "description": "Saved search ID", "example": "507f1f77bcf86cd799439011" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SavedSearchInput" } } } }, "responses": { "200": { "description": "Successfully updated saved search", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SavedSearchResponseEnvelope" } } } }, "400": { "description": "Bad request", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Saved search not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "delete": { "summary": "Delete Saved Search", "description": "Deletes a saved search and any alerts attached to it.", "operationId": "deleteSavedSearch", "tags": [ "Saved Searches" ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "description": "Saved search ID", "example": "507f1f77bcf86cd799439011" } ], "responses": { "200": { "description": "Successfully deleted saved search", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EmptyResponse" }, "example": {} } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Saved search not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/api/v2/search": { "post": { "summary": "Search Raw Logs and Traces", "description": "Fetch individual log or trace rows from a HyperDX source.\n\nThis endpoint mirrors the \"search\" panel mode in the HyperDX UI.\nHyperDX applies the same query optimizations used in the UI:\n - Named attribute columns (e.g. \"pipedream.pipeline_name\") are\n rewritten to their indexed materialized equivalents when the\n source schema exposes them, avoiding slow Map lookups.\n - Rows are ordered by timestamp descending (most recent first).\n - The source's built-in PREWHERE / partition pruning is applied.\n\nAuthentication: Bearer token (personal API key from Team Settings).\n", "operationId": "searchEvents", "tags": [ "Search" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SearchRequest" }, "examples": { "recentErrors": { "summary": "Recent errors for a service", "value": { "sourceId": "69b46cb0d964ce2d0b9506a8", "startTime": "2026-05-10T00:00:00Z", "endTime": "2026-05-10T01:00:00Z", "where": "SeverityText:ERROR", "select": "Timestamp,SeverityText,Body,ServiceName", "maxResults": 50 } }, "pipedreamTaskLogs": { "summary": "Pipedream task logs with materialized column filter", "value": { "sourceId": "69b46cb0d964ce2d0b9506a8", "startTime": "2026-05-10T00:00:00Z", "endTime": "2026-05-10T01:00:00Z", "where": "pipedream.pipeline_name:my-pipeline", "select": "Timestamp,SeverityText,Body,pipedream.pipeline_name,pipedream.stage_name,pipedream.task_index", "maxResults": 200 } }, "traceSearch": { "summary": "Slow spans for a service", "value": { "sourceId": "69b46cb0d964ce2d0b9508b2", "startTime": "2026-05-10T00:00:00Z", "endTime": "2026-05-10T01:00:00Z", "where": "ServiceName:my-service AND Duration:>1000000000", "select": "Timestamp,TraceId,SpanId,SpanName,ServiceName,Duration,StatusCode", "maxResults": 100 } }, "paginated": { "summary": "Paginated fetch", "value": { "sourceId": "69b46cb0d964ce2d0b9506a8", "startTime": "2026-05-10T00:00:00Z", "endTime": "2026-05-10T01:00:00Z", "maxResults": 100, "offset": 100 } } } } } }, "responses": { "200": { "description": "Matching rows returned successfully", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SearchResponse" }, "example": { "data": [ { "Timestamp": "2026-05-10T00:01:23.456789000Z", "SeverityText": "ERROR", "Body": "connection refused: redis:6379", "ServiceName": "api-service" } ], "rows": 1 } } } }, "400": { "description": "Invalid request parameters or query error", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string" } } } } } }, "401": { "description": "Missing or invalid API key" }, "404": { "description": "Source or connection not found", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string" } } } } } }, "500": { "description": "Server error", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string" } } } } } } } } }, "/api/v2/sources": { "get": { "summary": "List Sources", "description": "Retrieves a list of all sources for the authenticated team", "operationId": "listSources", "tags": [ "Sources" ], "responses": { "200": { "description": "Successfully retrieved sources", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SourcesListResponse" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "message": "Unauthorized access. API key is missing or invalid." } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "post": { "summary": "Create Source", "description": "Creates a new source.\n\nThe request body is a source object without the `id` field. If an\n`id` is sent anyway it is silently ignored (stripped before\nvalidation — the request is never rejected because of it).\nGranularity fields\n(`materializedViews[].minGranularity` and\n`metadataMaterializedViews.granularity`) accept the same short format\nthe API returns (e.g. `5m`, `15s`, `1h`, `1d`).\n", "operationId": "createSource", "tags": [ "Sources" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Source" } } } }, "responses": { "200": { "description": "Successfully created source", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SourceResponseEnvelope" } } } }, "400": { "description": "Bad request", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "message": "Body validation failed: name: Required" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "message": "Unauthorized access. API key is missing or invalid." } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/api/v2/sources/{id}": { "get": { "summary": "Get Source", "description": "Retrieves a specific source by ID", "operationId": "getSource", "tags": [ "Sources" ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "description": "Source ID", "example": "507f1f77bcf86cd799439011" } ], "responses": { "200": { "description": "Successfully retrieved source", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SourceResponseEnvelope" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "message": "Unauthorized access. API key is missing or invalid." } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Source not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "message": "Source not found" } } } } } }, "put": { "summary": "Update Source", "description": "Updates an existing source. The full source object must be provided;\nthis is a replace, not a patch.\n\nThe request body is a source object without the `id` field. If an\n`id` is sent anyway it is silently ignored (stripped before\nvalidation — never a 400); the path parameter alone identifies the\nsource. Granularity fields (`materializedViews[].minGranularity` and\n`metadataMaterializedViews.granularity`) accept the same short format\nthe API returns (e.g. `5m`, `15s`, `1h`, `1d`).\n", "operationId": "updateSource", "tags": [ "Sources" ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "description": "Source ID", "example": "507f1f77bcf86cd799439011" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Source" } } } }, "responses": { "200": { "description": "Successfully updated source", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SourceResponseEnvelope" } } } }, "400": { "description": "Bad request", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "message": "Body validation failed: name: Required" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "message": "Unauthorized access. API key is missing or invalid." } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Source not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "message": "Source not found" } } } } } }, "delete": { "summary": "Delete Source", "description": "Deletes a source", "operationId": "deleteSource", "tags": [ "Sources" ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "description": "Source ID", "example": "507f1f77bcf86cd799439011" } ], "responses": { "200": { "description": "Successfully deleted source", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EmptyResponse" }, "example": {} } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "message": "Unauthorized access. API key is missing or invalid." } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Source not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "message": "Source not found" } } } } } } }, "/api/v2/team": { "get": { "summary": "Get Team", "description": "Retrieves the authenticated team's basic settings.", "operationId": "getTeam", "tags": [ "Team" ], "responses": { "200": { "description": "Successfully retrieved team" }, "403": { "description": "Forbidden" } } } }, "/api/v2/team/members": { "get": { "summary": "List Team Members", "description": "Retrieves the team's members.", "operationId": "listTeamMembers", "tags": [ "Team" ], "responses": { "200": { "description": "Successfully retrieved members" } } } }, "/api/v2/team/invitation": { "post": { "summary": "Invite Team Member", "description": "Creates a pending invitation for a new email address.", "operationId": "inviteTeamMember", "tags": [ "Team" ], "responses": { "200": { "description": "Successfully created the invitation" }, "400": { "description": "User already exists" } } } }, "/api/v2/team/invitations": { "get": { "summary": "List Team Invitations", "description": "Retrieves the team's pending invitations.", "operationId": "listTeamInvitations", "tags": [ "Team" ], "responses": { "200": { "description": "Successfully retrieved invitations" } } } }, "/api/v2/team/invitation/{id}": { "delete": { "summary": "Delete Team Invitation", "description": "Deletes a pending team invitation.", "operationId": "deleteTeamInvitation", "tags": [ "Team" ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "Successfully deleted the invitation" }, "404": { "description": "Invitation not found" } } } }, "/api/v2/team/member/{id}": { "delete": { "summary": "Remove Team Member", "description": "Removes a member from the team.", "operationId": "removeTeamMember", "tags": [ "Team" ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "Successfully removed the member" }, "400": { "description": "Cannot remove yourself from the team" }, "404": { "description": "Member not found" } } } }, "/api/v2/webhooks": { "get": { "summary": "List Webhooks", "description": "Retrieves webhooks for the authenticated team (paginated). Results are capped at `limit` (default and maximum 1000). When more records exist than are returned, `meta.total` exceeds `data.length`; clients with large collections must page with `limit`/`offset` to retrieve them all.", "operationId": "listWebhooks", "tags": [ "Webhooks" ], "parameters": [ { "name": "limit", "in": "query", "required": false, "schema": { "type": "integer", "minimum": 1, "maximum": 1000, "default": 1000 }, "description": "Maximum number of webhooks to return." }, { "name": "offset", "in": "query", "required": false, "schema": { "type": "integer", "minimum": 0, "default": 0 }, "description": "Number of webhooks to skip before returning results." } ], "responses": { "200": { "description": "Successfully retrieved webhooks", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WebhooksListResponse" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "message": "Unauthorized access. API key is missing or invalid." } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "post": { "summary": "Create Webhook", "description": "Creates a new webhook for the authenticated team.", "operationId": "createWebhook", "tags": [ "Webhooks" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WebhookInput" } } } }, "responses": { "200": { "description": "Successfully created webhook", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WebhookResponseEnvelope" } } } }, "400": { "description": "Bad request or duplicate webhook", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/api/v2/webhooks/{id}": { "put": { "summary": "Update Webhook", "description": "Replaces an existing webhook. Readable optional fields\n(`description`, `body`) are a full replace: omitting them clears\nthem. The write-only fields `headers` and `queryParams` are never\nreturned on read, so omitting them preserves the stored values;\nsend an explicit empty object (`{}`) to clear them. Exception: if the\ndestination (`url` or `service`) changes, omitted `headers`/\n`queryParams` are cleared rather than preserved so stored secrets are\nnever forwarded to a new destination.\n", "operationId": "updateWebhook", "tags": [ "Webhooks" ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "description": "Webhook ID", "example": "507f1f77bcf86cd799439011" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WebhookInput" } } } }, "responses": { "200": { "description": "Successfully updated webhook", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WebhookResponseEnvelope" } } } }, "400": { "description": "Bad request or duplicate webhook", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Webhook not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Webhook was modified concurrently; retry with current state", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "delete": { "summary": "Delete Webhook", "description": "Deletes a webhook. Blocked with a 409 while any alert still references it — reassign or remove those alerts first — so deletion never leaves an alert pointing at a missing webhook (which would silently drop notifications). Mirrors the internal webhook delete guard.", "operationId": "deleteWebhook", "tags": [ "Webhooks" ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "description": "Webhook ID", "example": "507f1f77bcf86cd799439011" } ], "responses": { "200": { "description": "Successfully deleted webhook", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EmptyResponse" }, "example": {} } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Webhook not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Webhook is still referenced by one or more alerts", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } } } }