diff --git a/docs/openapi/monitoring-api.json b/docs/openapi/monitoring-api.json index a9b7d44..9c8e8bd 100644 --- a/docs/openapi/monitoring-api.json +++ b/docs/openapi/monitoring-api.json @@ -196,7 +196,9 @@ "zapier", "datadog", "jira", - "gitlab" + "gitlab", + "sms", + "phone_call" ] } }, @@ -891,13 +893,13 @@ } } }, - "/api/v1/alert-channels/{id}/test": { - "post": { + "/api/v1/alert-channels/{id}/enabled": { + "patch": { "tags": [ "Alert Channels" ], - "summary": "Test a saved alert channel's connectivity", - "operationId": "test_2", + "summary": "Enable or disable an alert channel without re-uploading config", + "operationId": "setEnabled", "parameters": [ { "name": "id", @@ -909,112 +911,11 @@ } } ], - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/SingleValueResponseTestChannelResult" - } - } - } - }, - "400": { - "description": "Bad request — the payload failed validation", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "401": { - "description": "Unauthorized — missing or invalid credentials", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "403": { - "description": "Forbidden — the actor lacks permission for this resource", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "404": { - "description": "Not found — the requested resource does not exist", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "409": { - "description": "Conflict — the request collides with current resource state", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "500": { - "description": "Internal server error — see the message field for details", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "502": { - "description": "Bad gateway — an upstream provider returned an error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "503": { - "description": "Service unavailable — try again shortly", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - } - } - } - }, - "/api/v1/alert-channels/test": { - "post": { - "tags": [ - "Alert Channels" - ], - "summary": "Test alert channel connectivity using raw config (no saved channel required)", - "operationId": "testConfig", "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/TestAlertChannelRequest" + "$ref": "#/components/schemas/SetEnabledRequest" } } }, @@ -1026,7 +927,7 @@ "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseTestChannelResult" + "$ref": "#/components/schemas/SingleValueResponseAlertChannelDto" } } } @@ -1114,14 +1015,13 @@ } } }, - "/api/v1/alert-deliveries/{id}/attempts": { - "get": { + "/api/v1/alert-channels/{id}/test": { + "post": { "tags": [ - "Alert Deliveries" + "Alert Channels" ], - "summary": "List delivery attempts for a specific alert delivery", - "description": "Returns the ordered list of delivery attempts (request/response audit data) for the given delivery ID.", - "operationId": "listAttempts", + "summary": "Test a saved alert channel's connectivity", + "operationId": "test_2", "parameters": [ { "name": "id", @@ -1139,7 +1039,7 @@ "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/TableValueResultDeliveryAttemptDto" + "$ref": "#/components/schemas/SingleValueResponseTestChannelResult" } } } @@ -1227,32 +1127,30 @@ } } }, - "/api/v1/alert-deliveries/{id}/retry": { + "/api/v1/alert-channels/test": { "post": { "tags": [ - "Alert Deliveries" + "Alert Channels" ], - "summary": "Retry a failed delivery", - "description": "Resets a FAILED delivery to RETRY_PENDING so the delivery worker re-attempts it.", - "operationId": "retry", - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "string", - "format": "uuid" + "summary": "Test alert channel connectivity using raw config (no saved channel required)", + "operationId": "testConfig", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TestAlertChannelRequest" + } } - } - ], + }, + "required": true + }, "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseAlertDeliveryDto" + "$ref": "#/components/schemas/SingleValueResponseTestChannelResult" } } } @@ -1340,20 +1238,32 @@ } } }, - "/api/v1/api-keys": { + "/api/v1/alert-deliveries/{id}/attempts": { "get": { "tags": [ - "API Keys" + "Alert Deliveries" + ], + "summary": "List delivery attempts for a specific alert delivery", + "description": "Returns the ordered list of delivery attempts (request/response audit data) for the given delivery ID.", + "operationId": "listAttempts", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } ], - "summary": "List API keys", - "operationId": "list_13", "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/TableValueResultApiKeyDto" + "$ref": "#/components/schemas/TableValueResultDeliveryAttemptDto" } } } @@ -1439,30 +1349,34 @@ } } } - }, + } + }, + "/api/v1/alert-deliveries/{id}/retry": { "post": { "tags": [ - "API Keys" + "Alert Deliveries" ], - "summary": "Create API key", - "operationId": "create_14", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateApiKeyRequest" - } + "summary": "Retry a failed delivery", + "description": "Resets a FAILED delivery to RETRY_PENDING so the delivery worker re-attempts it.", + "operationId": "retry", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" } - }, - "required": true - }, + } + ], "responses": { - "201": { - "description": "Created", + "200": { + "description": "OK", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseApiKeyCreateResponse" + "$ref": "#/components/schemas/SingleValueResponseAlertDeliveryDto" } } } @@ -1550,27 +1464,23 @@ } } }, - "/api/v1/api-keys/{id}": { - "delete": { + "/api/v1/api-keys": { + "get": { "tags": [ "API Keys" ], - "summary": "Delete API key", - "operationId": "delete_11", - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], + "summary": "List API keys", + "operationId": "list_13", "responses": { - "204": { - "description": "No Content" + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/TableValueResultApiKeyDto" + } + } + } }, "400": { "description": "Bad request — the payload failed validation", @@ -1654,40 +1564,254 @@ } } }, - "patch": { + "post": { "tags": [ "API Keys" ], - "summary": "Update API key", - "operationId": "update_15", - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], + "summary": "Create API key", + "operationId": "create_14", "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/UpdateApiKeyRequest" + "$ref": "#/components/schemas/CreateApiKeyRequest" } } }, "required": true }, "responses": { - "200": { - "description": "OK", + "201": { + "description": "Created", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseApiKeyDto" + "$ref": "#/components/schemas/SingleValueResponseApiKeyCreateResponse" + } + } + } + }, + "400": { + "description": "Bad request — the payload failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized — missing or invalid credentials", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden — the actor lacks permission for this resource", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Not found — the requested resource does not exist", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict — the request collides with current resource state", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error — see the message field for details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "502": { + "description": "Bad gateway — an upstream provider returned an error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "503": { + "description": "Service unavailable — try again shortly", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/api/v1/api-keys/{id}": { + "delete": { + "tags": [ + "API Keys" + ], + "summary": "Delete API key", + "operationId": "delete_11", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "400": { + "description": "Bad request — the payload failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized — missing or invalid credentials", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden — the actor lacks permission for this resource", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Not found — the requested resource does not exist", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict — the request collides with current resource state", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error — see the message field for details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "502": { + "description": "Bad gateway — an upstream provider returned an error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "503": { + "description": "Service unavailable — try again shortly", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + }, + "patch": { + "tags": [ + "API Keys" + ], + "summary": "Update API key", + "operationId": "update_16", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateApiKeyRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/SingleValueResponseApiKeyDto" } } } @@ -2005,7 +2129,7 @@ "Audit Log" ], "summary": "List audit events for the current organization", - "operationId": "list_19", + "operationId": "list_20", "parameters": [ { "name": "action", @@ -4545,7 +4669,7 @@ "Incidents" ], "summary": "Get incident details including update timeline", - "operationId": "get_11", + "operationId": "get_9", "parameters": [ { "name": "id", @@ -4649,15 +4773,13 @@ } } } - } - }, - "/api/v1/incidents/{id}/resolve": { - "post": { + }, + "patch": { "tags": [ "Incidents" ], - "summary": "Resolve an incident", - "operationId": "resolve", + "summary": "Update incident title and/or severity", + "operationId": "update_15", "parameters": [ { "name": "id", @@ -4673,10 +4795,11 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ResolveIncidentRequest" + "$ref": "#/components/schemas/UpdateIncidentRequest" } } - } + }, + "required": true }, "responses": { "200": { @@ -4772,13 +4895,14 @@ } } }, - "/api/v1/incidents/{id}/updates": { + "/api/v1/incidents/{id}/acknowledge": { "post": { "tags": [ "Incidents" ], - "summary": "Add an update to an incident (optionally change status)", - "operationId": "addUpdate", + "summary": "Acknowledge all open notification dispatches for an incident", + "description": "Atomically acknowledges every DELIVERED or ESCALATING dispatch for the incident. Already-acknowledged and non-acknowledgeable dispatches are returned in skipped (not errors). MEMBER+.", + "operationId": "acknowledgeAll", "parameters": [ { "name": "id", @@ -4790,23 +4914,13 @@ } } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AddIncidentUpdateRequest" - } - } - }, - "required": true - }, "responses": { - "201": { - "description": "Created", + "200": { + "description": "OK", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseIncidentDetailDto" + "$ref": "#/components/schemas/SingleValueResponseAcknowledgeAllIncidentsResponse" } } } @@ -4894,21 +5008,50 @@ } } }, - "/api/v1/integrations": { + "/api/v1/incidents/{id}/events": { "get": { "tags": [ - "Integrations" + "Incidents" + ], + "summary": "List merged activity events for an incident", + "description": "Cursor-paginated unified activity stream merging incident updates, notification dispatches, alert deliveries, forensic state transitions, and linked status-page updates. Ordered by time descending.", + "operationId": "listEvents_1", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "cursor", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "format": "int32", + "default": 50 + } + } ], - "summary": "List all supported integration types", - "description": "Returns the full static catalog of supported alert channel integration types with their metadata and config field schemas. Used by the frontend to dynamically render the 'Add Alert Channel' form.", - "operationId": "list_18", "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/TableValueResultIntegrationDto" + "$ref": "#/components/schemas/CursorPageIncidentActivityEventDto" } } } @@ -4996,20 +5139,52 @@ } } }, - "/api/v1/invites": { + "/api/v1/incidents/{id}/related": { "get": { "tags": [ - "Invites" + "Incidents" + ], + "summary": "List related incidents sharing the same origin", + "description": "Returns same-origin recurrence (monitor, service, or resource group) within the window, excluding the current incident. total is the full count for “Nth outage this month” copy.", + "operationId": "listRelated", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "windowDays", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "format": "int32", + "default": 30 + } + }, + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "format": "int32", + "default": 3 + } + } ], - "summary": "List invites", - "operationId": "list_10", "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/TableValueResultInviteDto" + "$ref": "#/components/schemas/RelatedIncidentsResponse" } } } @@ -5095,30 +5270,42 @@ } } } - }, + } + }, + "/api/v1/incidents/{id}/resolve": { "post": { "tags": [ - "Invites" + "Incidents" + ], + "summary": "Resolve an incident", + "operationId": "resolve", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } ], - "summary": "Create invite", - "operationId": "create_11", "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/CreateInviteRequest" + "$ref": "#/components/schemas/ResolveIncidentRequest" } } - }, - "required": true + } }, "responses": { - "201": { - "description": "Created", + "200": { + "description": "OK", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseInviteDto" + "$ref": "#/components/schemas/SingleValueResponseIncidentDetailDto" } } } @@ -5206,31 +5393,41 @@ } } }, - "/api/v1/invites/{inviteId}/resend": { + "/api/v1/incidents/{id}/updates": { "post": { "tags": [ - "Invites" + "Incidents" ], - "summary": "Resend invite", - "operationId": "resend_1", + "summary": "Add an update to an incident (optionally change status)", + "operationId": "addUpdate", "parameters": [ { - "name": "inviteId", + "name": "id", "in": "path", "required": true, "schema": { - "type": "integer", - "format": "int32" + "type": "string", + "format": "uuid" } } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddIncidentUpdateRequest" + } + } + }, + "required": true + }, "responses": { - "200": { - "description": "OK", + "201": { + "description": "Created", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseInviteDto" + "$ref": "#/components/schemas/SingleValueResponseIncidentDetailDto" } } } @@ -5318,27 +5515,24 @@ } } }, - "/api/v1/invites/{inviteId}/revoke": { - "post": { + "/api/v1/integrations": { + "get": { "tags": [ - "Invites" - ], - "summary": "Revoke invite", - "operationId": "revoke", - "parameters": [ - { - "name": "inviteId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } + "Integrations" ], + "summary": "List all supported integration types", + "description": "Returns the full static catalog of supported alert channel integration types with their metadata and config field schemas. Used by the frontend to dynamically render the 'Add Alert Channel' form.", + "operationId": "list_19", "responses": { - "204": { - "description": "No Content" + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/TableValueResultIntegrationDto" + } + } + } }, "400": { "description": "Bad request — the payload failed validation", @@ -5423,42 +5617,21 @@ } } }, - "/api/v1/maintenance-windows": { + "/api/v1/integrations/voice-languages": { "get": { "tags": [ - "Maintenance Windows" - ], - "summary": "List maintenance windows for the authenticated org", - "description": "Returns maintenance windows for the caller's organisation. Optionally filter by monitor_id, and/or by status: 'active' (currently in window) or 'upcoming' (starts in the future).", - "operationId": "list_9", - "parameters": [ - { - "name": "monitorId", - "in": "query", - "description": "Filter by monitor UUID", - "required": false, - "schema": { - "type": "string", - "format": "uuid" - } - }, - { - "name": "filter", - "in": "query", - "description": "Filter by status: 'active' or 'upcoming'", - "required": false, - "schema": { - "type": "string" - } - } + "Integrations" ], + "summary": "List supported voice languages for phone call alerts", + "description": "Returns BCP-47 locale codes and human-readable labels for all TTS languages supported by the phone call alert channel.", + "operationId": "listVoiceLanguages", "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/TableValueResultMaintenanceWindowDto" + "$ref": "#/components/schemas/TableValueResultVoiceLanguageDto" } } } @@ -5544,31 +5717,22 @@ } } } - }, - "post": { + } + }, + "/api/v1/invites": { + "get": { "tags": [ - "Maintenance Windows" + "Invites" ], - "summary": "Create a maintenance window", - "description": "Creates a new maintenance window. Set monitorId to null to create an org-wide window that suppresses alerts for all monitors.", - "operationId": "create_10", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateMaintenanceWindowRequest" - } - } - }, - "required": true - }, + "summary": "List invites", + "operationId": "list_10", "responses": { - "201": { - "description": "Created", + "200": { + "description": "OK", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseMaintenanceWindowDto" + "$ref": "#/components/schemas/TableValueResultInviteDto" } } } @@ -5654,33 +5818,30 @@ } } } - } - }, - "/api/v1/maintenance-windows/{id}": { - "get": { + }, + "post": { "tags": [ - "Maintenance Windows" + "Invites" ], - "summary": "Get a single maintenance window by ID", - "operationId": "getById_2", - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "string", - "format": "uuid" + "summary": "Create invite", + "operationId": "create_11", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateInviteRequest" + } } - } - ], + }, + "required": true + }, "responses": { - "200": { - "description": "OK", + "201": { + "description": "Created", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseMaintenanceWindowDto" + "$ref": "#/components/schemas/SingleValueResponseInviteDto" } } } @@ -5766,41 +5927,33 @@ } } } - }, - "put": { + } + }, + "/api/v1/invites/{inviteId}/resend": { + "post": { "tags": [ - "Maintenance Windows" + "Invites" ], - "summary": "Update a maintenance window", - "operationId": "update_12", + "summary": "Resend invite", + "operationId": "resend_1", "parameters": [ { - "name": "id", + "name": "inviteId", "in": "path", "required": true, "schema": { - "type": "string", - "format": "uuid" + "type": "integer", + "format": "int32" } } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateMaintenanceWindowRequest" - } - } - }, - "required": true - }, "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseMaintenanceWindowDto" + "$ref": "#/components/schemas/SingleValueResponseInviteDto" } } } @@ -5886,21 +6039,23 @@ } } } - }, - "delete": { + } + }, + "/api/v1/invites/{inviteId}/revoke": { + "post": { "tags": [ - "Maintenance Windows" + "Invites" ], - "summary": "Delete a maintenance window", - "operationId": "delete_8", + "summary": "Revoke invite", + "operationId": "revoke", "parameters": [ { - "name": "id", + "name": "inviteId", "in": "path", "required": true, "schema": { - "type": "string", - "format": "uuid" + "type": "integer", + "format": "int32" } } ], @@ -5991,20 +6146,32 @@ } } }, - "/api/v1/members": { + "/api/v1/maintenance-windows": { "get": { "tags": [ - "Members" + "Maintenance Windows" ], - "summary": "List organization members", - "operationId": "list_17", + "summary": "List maintenance windows for the authenticated org", + "description": "Returns maintenance windows for the caller's organisation. Optionally filter by monitor_id, and/or by status: 'active' (currently in window) or 'upcoming' (starts in the future).", + "operationId": "list_9", "parameters": [ { - "name": "pageable", + "name": "monitorId", "in": "query", - "required": true, + "description": "Filter by monitor UUID", + "required": false, "schema": { - "$ref": "#/components/schemas/Pageable" + "type": "string", + "format": "uuid" + } + }, + { + "name": "filter", + "in": "query", + "description": "Filter by status: 'active' or 'upcoming'", + "required": false, + "schema": { + "type": "string" } } ], @@ -6014,7 +6181,117 @@ "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/TableValueResultMemberDto" + "$ref": "#/components/schemas/TableValueResultMaintenanceWindowDto" + } + } + } + }, + "400": { + "description": "Bad request — the payload failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized — missing or invalid credentials", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden — the actor lacks permission for this resource", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Not found — the requested resource does not exist", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict — the request collides with current resource state", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error — see the message field for details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "502": { + "description": "Bad gateway — an upstream provider returned an error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "503": { + "description": "Service unavailable — try again shortly", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + }, + "post": { + "tags": [ + "Maintenance Windows" + ], + "summary": "Create a maintenance window", + "description": "Creates a new maintenance window. Set monitorId to null to create an org-wide window that suppresses alerts for all monitors.", + "operationId": "create_10", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateMaintenanceWindowRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Created", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/SingleValueResponseMaintenanceWindowDto" } } } @@ -6102,27 +6379,34 @@ } } }, - "/api/v1/members/{userId}": { - "delete": { + "/api/v1/maintenance-windows/{id}": { + "get": { "tags": [ - "Members" + "Maintenance Windows" ], - "summary": "Remove member from organization", - "operationId": "remove_2", + "summary": "Get a single maintenance window by ID", + "operationId": "getById_2", "parameters": [ { - "name": "userId", + "name": "id", "in": "path", "required": true, "schema": { - "type": "integer", - "format": "int32" + "type": "string", + "format": "uuid" } } ], "responses": { - "204": { - "description": "No Content" + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/SingleValueResponseMaintenanceWindowDto" + } + } + } }, "400": { "description": "Bad request — the payload failed validation", @@ -6205,23 +6489,21 @@ } } } - } - }, - "/api/v1/members/{userId}/role": { + }, "put": { "tags": [ - "Members" + "Maintenance Windows" ], - "summary": "Change member role", - "operationId": "changeRole", + "summary": "Update a maintenance window", + "operationId": "update_12", "parameters": [ { - "name": "userId", + "name": "id", "in": "path", "required": true, "schema": { - "type": "integer", - "format": "int32" + "type": "string", + "format": "uuid" } } ], @@ -6229,15 +6511,22 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ChangeRoleRequest" + "$ref": "#/components/schemas/UpdateMaintenanceWindowRequest" } } }, "required": true }, "responses": { - "204": { - "description": "No Content" + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/SingleValueResponseMaintenanceWindowDto" + } + } + } }, "400": { "description": "Bad request — the payload failed validation", @@ -6320,36 +6609,24 @@ } } } - } - }, - "/api/v1/members/{userId}/status": { - "put": { + }, + "delete": { "tags": [ - "Members" + "Maintenance Windows" ], - "summary": "Change member status", - "operationId": "changeStatus", + "summary": "Delete a maintenance window", + "operationId": "delete_8", "parameters": [ { - "name": "userId", + "name": "id", "in": "path", "required": true, "schema": { - "type": "integer", - "format": "int32" + "type": "string", + "format": "uuid" } } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ChangeStatusRequest" - } - } - }, - "required": true - }, "responses": { "204": { "description": "No Content" @@ -6437,103 +6714,14 @@ } } }, - "/api/v1/monitors": { + "/api/v1/members": { "get": { "tags": [ - "Monitors" + "Members" ], - "summary": "List monitors for the authenticated org", - "description": "Supports filtering by `enabled`, `status` (alias active|paused for enabled), `type`, `managedBy`, `tag` / `tags`, `search`, and `environmentId`. Unrecognised query parameters are silently ignored (Spring's default binding behaviour) — pin to the documented set above.", - "operationId": "list_8", + "summary": "List organization members", + "operationId": "list_18", "parameters": [ - { - "name": "enabled", - "in": "query", - "description": "Filter by enabled state (true/false)", - "required": false, - "schema": { - "type": "boolean" - } - }, - { - "name": "status", - "in": "query", - "description": "Lifecycle status alias: 'active' (enabled=true) or 'paused' (enabled=false). Ignored when ?enabled is also supplied.", - "required": false, - "schema": { - "type": "string" - } - }, - { - "name": "type", - "in": "query", - "description": "Filter by monitor type", - "required": false, - "schema": { - "type": "string", - "enum": [ - "HTTP", - "DNS", - "MCP_SERVER", - "TCP", - "ICMP", - "HEARTBEAT" - ] - } - }, - { - "name": "managedBy", - "in": "query", - "description": "Filter by managed-by source", - "required": false, - "schema": { - "type": "string", - "enum": [ - "DASHBOARD", - "CLI", - "TERRAFORM", - "MCP", - "API" - ] - } - }, - { - "name": "tags", - "in": "query", - "description": "Filter by tag names, comma-separated (e.g. prod,critical); OR semantics", - "required": false, - "schema": { - "type": "string" - } - }, - { - "name": "tag", - "in": "query", - "description": "Filter by a single tag name (alias for ?tags=); merged with ?tags using OR semantics", - "required": false, - "schema": { - "type": "string" - } - }, - { - "name": "search", - "in": "query", - "description": "Case-insensitive name search", - "required": false, - "schema": { - "type": "string" - } - }, - { - "name": "environmentId", - "in": "query", - "description": "Filter by environment ID", - "required": false, - "schema": { - "type": "string", - "format": "uuid" - } - }, { "name": "pageable", "in": "query", @@ -6549,7 +6737,7 @@ "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/TableValueResultMonitorDto" + "$ref": "#/components/schemas/TableValueResultMemberDto" } } } @@ -6635,33 +6823,29 @@ } } } - }, - "post": { + } + }, + "/api/v1/members/{userId}": { + "delete": { "tags": [ - "Monitors" + "Members" ], - "summary": "Create a new monitor", - "operationId": "create_9", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateMonitorRequest" - } + "summary": "Remove member from organization", + "operationId": "remove_2", + "parameters": [ + { + "name": "userId", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" } - }, - "required": true - }, + } + ], "responses": { - "201": { - "description": "Created", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/SingleValueResponseMonitorDto" - } - } - } + "204": { + "description": "No Content" }, "400": { "description": "Bad request — the payload failed validation", @@ -6746,35 +6930,38 @@ } } }, - "/api/v1/monitors/{id}": { - "get": { + "/api/v1/members/{userId}/role": { + "put": { "tags": [ - "Monitors" + "Members" ], - "summary": "Get a single monitor by id", - "operationId": "get_6", + "summary": "Change member role", + "operationId": "changeRole", "parameters": [ { - "name": "id", + "name": "userId", "in": "path", "required": true, "schema": { - "type": "string", - "format": "uuid" + "type": "integer", + "format": "int32" } } ], - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/SingleValueResponseMonitorDto" - } + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChangeRoleRequest" } } }, + "required": true + }, + "responses": { + "204": { + "description": "No Content" + }, "400": { "description": "Bad request — the payload failed validation", "content": { @@ -6856,21 +7043,23 @@ } } } - }, + } + }, + "/api/v1/members/{userId}/status": { "put": { "tags": [ - "Monitors" + "Members" ], - "summary": "Update a monitor", - "operationId": "update_11", + "summary": "Change member status", + "operationId": "changeStatus", "parameters": [ { - "name": "id", + "name": "userId", "in": "path", "required": true, "schema": { - "type": "string", - "format": "uuid" + "type": "integer", + "format": "int32" } } ], @@ -6878,22 +7067,15 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/UpdateMonitorRequest" + "$ref": "#/components/schemas/ChangeStatusRequest" } } }, "required": true }, "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/SingleValueResponseMonitorDto" - } - } - } + "204": { + "description": "No Content" }, "400": { "description": "Bad request — the payload failed validation", @@ -6976,27 +7158,126 @@ } } } - }, - "delete": { + } + }, + "/api/v1/monitors": { + "get": { "tags": [ "Monitors" ], - "summary": "Soft-delete a monitor", - "operationId": "delete_7", + "summary": "List monitors for the authenticated org", + "description": "Supports filtering by `enabled`, `status` (alias active|paused for enabled), `type`, `managedBy`, `tag` / `tags`, `search`, and `environmentId`. Unrecognised query parameters are silently ignored (Spring's default binding behaviour) — pin to the documented set above.", + "operationId": "list_8", "parameters": [ { - "name": "id", - "in": "path", - "required": true, + "name": "enabled", + "in": "query", + "description": "Filter by enabled state (true/false)", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "name": "status", + "in": "query", + "description": "Lifecycle status alias: 'active' (enabled=true) or 'paused' (enabled=false). Ignored when ?enabled is also supplied.", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "type", + "in": "query", + "description": "Filter by monitor type", + "required": false, + "schema": { + "type": "string", + "enum": [ + "HTTP", + "DNS", + "MCP_SERVER", + "TCP", + "ICMP", + "HEARTBEAT", + "BROWSER", + "MULTI_STEP_API" + ] + } + }, + { + "name": "managedBy", + "in": "query", + "description": "Filter by managed-by source", + "required": false, + "schema": { + "type": "string", + "enum": [ + "DASHBOARD", + "CLI", + "TERRAFORM", + "MCP", + "API" + ] + } + }, + { + "name": "tags", + "in": "query", + "description": "Filter by tag names, comma-separated (e.g. prod,critical); OR semantics", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "tag", + "in": "query", + "description": "Filter by a single tag name (alias for ?tags=); merged with ?tags using OR semantics", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "search", + "in": "query", + "description": "Case-insensitive name search", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "environmentId", + "in": "query", + "description": "Filter by environment ID", + "required": false, "schema": { "type": "string", "format": "uuid" } + }, + { + "name": "pageable", + "in": "query", + "required": true, + "schema": { + "$ref": "#/components/schemas/Pageable" + } } ], "responses": { - "204": { - "description": "No Content" + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/TableValueResultMonitorDto" + } + } + } }, "400": { "description": "Bad request — the payload failed validation", @@ -7079,29 +7360,26 @@ } } } - } - }, - "/api/v1/monitors/{id}/pause": { + }, "post": { "tags": [ "Monitors" ], - "summary": "Pause a monitor (set enabled=false)", - "operationId": "pause", - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "string", - "format": "uuid" + "summary": "Create a new monitor", + "operationId": "create_9", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateMonitorRequest" + } } - } - ], + }, + "required": true + }, "responses": { - "200": { - "description": "OK", + "201": { + "description": "Created", "content": { "*/*": { "schema": { @@ -7193,14 +7471,13 @@ } } }, - "/api/v1/monitors/{id}/results": { + "/api/v1/monitors/{id}": { "get": { "tags": [ - "Check Results" + "Monitors" ], - "summary": "List raw check results", - "description": "Returns check results for the given monitor with optional time-range, region, and pass/fail filtering. Uses cursor-based pagination — pass the returned `cursor` value on subsequent requests to retrieve the next page. The cursor encodes the original time bounds, so `from`/`to` are ignored when a cursor is present.", - "operationId": "getResults", + "summary": "Get a single monitor by id", + "operationId": "get_6", "parameters": [ { "name": "id", @@ -7210,84 +7487,25 @@ "type": "string", "format": "uuid" } - }, - { - "name": "from", - "in": "query", - "description": "Start of time range (ISO 8601, inclusive); defaults to 24 hours ago", - "required": false, - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "to", - "in": "query", - "description": "End of time range (ISO 8601, inclusive); defaults to now", - "required": false, - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "cursor", - "in": "query", - "description": "Opaque cursor from a previous response for pagination", - "required": false, - "schema": { - "type": "string" - } - }, - { - "name": "limit", - "in": "query", - "description": "Maximum results per page (1–200)", - "required": false, - "schema": { - "type": "integer", - "format": "int32", - "default": 50 - }, - "example": 50 - }, - { - "name": "region", - "in": "query", - "description": "Filter by region (e.g. us-east)", - "required": false, - "schema": { - "type": "string" - } - }, - { - "name": "passed", - "in": "query", - "description": "Filter by pass/fail status", - "required": false, - "schema": { - "type": "boolean" - } } ], "responses": { "200": { - "description": "Paginated check results", + "description": "OK", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/CursorPageCheckResultDto" + "$ref": "#/components/schemas/SingleValueResponseMonitorDto" } } } }, "400": { - "description": "Invalid query parameters", + "description": "Bad request — the payload failed validation", "content": { - "*/*": { + "application/json": { "schema": { - "$ref": "#/components/schemas/CursorPageCheckResultDto" + "$ref": "#/components/schemas/ErrorResponse" } } } @@ -7303,21 +7521,21 @@ } }, "403": { - "description": "Monitor does not belong to the caller's org", + "description": "Forbidden — the actor lacks permission for this resource", "content": { - "*/*": { + "application/json": { "schema": { - "$ref": "#/components/schemas/CursorPageCheckResultDto" + "$ref": "#/components/schemas/ErrorResponse" } } } }, "404": { - "description": "Monitor not found", + "description": "Not found — the requested resource does not exist", "content": { - "*/*": { + "application/json": { "schema": { - "$ref": "#/components/schemas/CursorPageCheckResultDto" + "$ref": "#/components/schemas/ErrorResponse" } } } @@ -7363,16 +7581,13 @@ } } } - } - }, - "/api/v1/monitors/{id}/results/summary": { - "get": { + }, + "put": { "tags": [ - "Check Results" + "Monitors" ], - "summary": "Get results summary", - "description": "Returns a dashboard summary for the monitor: current status derived from the latest result per region, time-bucketed chart data, the 24-hour uptime percentage, and the selected window's uptime percentage.", - "operationId": "getSummary", + "summary": "Update a monitor", + "operationId": "update_11", "parameters": [ { "name": "id", @@ -7382,40 +7597,35 @@ "type": "string", "format": "uuid" } - }, - { - "name": "chartWindow", - "in": "query", - "description": "Chart window: 24h returns hourly buckets, 7d/30d/90d return daily buckets", - "required": false, - "schema": { - "type": "string", - "enum": [ - "24h", - "7d", - "30d", - "90d" - ] - } } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateMonitorRequest" + } + } + }, + "required": true + }, "responses": { "200": { - "description": "Results summary", + "description": "OK", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/ResultSummaryDto" + "$ref": "#/components/schemas/SingleValueResponseMonitorDto" } } } }, "400": { - "description": "Invalid chartWindow parameter", + "description": "Bad request — the payload failed validation", "content": { - "*/*": { + "application/json": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseResultSummaryDto" + "$ref": "#/components/schemas/ErrorResponse" } } } @@ -7431,21 +7641,21 @@ } }, "403": { - "description": "Monitor does not belong to the caller's org", + "description": "Forbidden — the actor lacks permission for this resource", "content": { - "*/*": { + "application/json": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseResultSummaryDto" + "$ref": "#/components/schemas/ErrorResponse" } } } }, "404": { - "description": "Monitor not found", + "description": "Not found — the requested resource does not exist", "content": { - "*/*": { + "application/json": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseResultSummaryDto" + "$ref": "#/components/schemas/ErrorResponse" } } } @@ -7491,15 +7701,13 @@ } } } - } - }, - "/api/v1/monitors/{id}/resume": { - "post": { + }, + "delete": { "tags": [ "Monitors" ], - "summary": "Resume a monitor (set enabled=true)", - "operationId": "resume", + "summary": "Soft-delete a monitor", + "operationId": "delete_7", "parameters": [ { "name": "id", @@ -7512,15 +7720,8 @@ } ], "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/SingleValueResponseMonitorDto" - } - } - } + "204": { + "description": "No Content" }, "400": { "description": "Bad request — the payload failed validation", @@ -7605,14 +7806,13 @@ } } }, - "/api/v1/monitors/{id}/rotate-token": { + "/api/v1/monitors/{id}/pause": { "post": { "tags": [ "Monitors" ], - "summary": "Rotate the ping token for a heartbeat monitor", - "description": "Generates a new ping token. The old token remains valid for 24 hours to allow cron jobs to be updated without downtime. Only supported for HEARTBEAT monitors.", - "operationId": "rotateToken", + "summary": "Pause a monitor (set enabled=false)", + "operationId": "pause", "parameters": [ { "name": "id", @@ -7718,13 +7918,14 @@ } } }, - "/api/v1/monitors/{id}/tags": { + "/api/v1/monitors/{id}/results": { "get": { "tags": [ - "Monitors" + "Check Results" ], - "summary": "Get all tags applied to a monitor", - "operationId": "getMonitorTags", + "summary": "List raw check results", + "description": "Returns check results for the given monitor with optional time-range, region, and pass/fail filtering. Uses cursor-based pagination — pass the returned `cursor` value on subsequent requests to retrieve the next page. The cursor encodes the original time bounds, so `from`/`to` are ignored when a cursor is present.", + "operationId": "getResults", "parameters": [ { "name": "id", @@ -7734,25 +7935,84 @@ "type": "string", "format": "uuid" } + }, + { + "name": "from", + "in": "query", + "description": "Start of time range (ISO 8601, inclusive); defaults to 24 hours ago", + "required": false, + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "to", + "in": "query", + "description": "End of time range (ISO 8601, inclusive); defaults to now", + "required": false, + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "cursor", + "in": "query", + "description": "Opaque cursor from a previous response for pagination", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "description": "Maximum results per page (1–200)", + "required": false, + "schema": { + "type": "integer", + "format": "int32", + "default": 50 + }, + "example": 50 + }, + { + "name": "region", + "in": "query", + "description": "Filter by region (e.g. us-east)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "passed", + "in": "query", + "description": "Filter by pass/fail status", + "required": false, + "schema": { + "type": "boolean" + } } ], "responses": { "200": { - "description": "OK", + "description": "Paginated check results", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/TableValueResultTagDto" + "$ref": "#/components/schemas/CursorPageCheckResultDto" } } } }, "400": { - "description": "Bad request — the payload failed validation", + "description": "Invalid query parameters", "content": { - "application/json": { + "*/*": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/CursorPageCheckResultDto" } } } @@ -7768,21 +8028,21 @@ } }, "403": { - "description": "Forbidden — the actor lacks permission for this resource", + "description": "Monitor does not belong to the caller's org", "content": { - "application/json": { + "*/*": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/CursorPageCheckResultDto" } } } }, "404": { - "description": "Not found — the requested resource does not exist", + "description": "Monitor not found", "content": { - "application/json": { + "*/*": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/CursorPageCheckResultDto" } } } @@ -7828,13 +8088,16 @@ } } } - }, - "post": { + } + }, + "/api/v1/monitors/{id}/results/summary": { + "get": { "tags": [ - "Monitors" + "Check Results" ], - "summary": "Add tags to a monitor; supports existing tag IDs and inline creation of new tags", - "operationId": "addMonitorTags", + "summary": "Get results summary", + "description": "Returns a dashboard summary for the monitor: current status derived from the latest result per region, time-bucketed chart data, the 24-hour uptime percentage, and the selected window's uptime percentage.", + "operationId": "getSummary", "parameters": [ { "name": "id", @@ -7844,35 +8107,40 @@ "type": "string", "format": "uuid" } + }, + { + "name": "chartWindow", + "in": "query", + "description": "Chart window: 24h returns hourly buckets, 7d/30d/90d return daily buckets", + "required": false, + "schema": { + "type": "string", + "enum": [ + "24h", + "7d", + "30d", + "90d" + ] + } } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AddMonitorTagsRequest" - } - } - }, - "required": true - }, "responses": { "200": { - "description": "OK", + "description": "Results summary", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/TableValueResultTagDto" + "$ref": "#/components/schemas/ResultSummaryDto" } } } }, "400": { - "description": "Bad request — the payload failed validation", + "description": "Invalid chartWindow parameter", "content": { - "application/json": { + "*/*": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/SingleValueResponseResultSummaryDto" } } } @@ -7888,21 +8156,21 @@ } }, "403": { - "description": "Forbidden — the actor lacks permission for this resource", + "description": "Monitor does not belong to the caller's org", "content": { - "application/json": { + "*/*": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/SingleValueResponseResultSummaryDto" } } } }, "404": { - "description": "Not found — the requested resource does not exist", + "description": "Monitor not found", "content": { - "application/json": { + "*/*": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/SingleValueResponseResultSummaryDto" } } } @@ -7948,13 +8216,15 @@ } } } - }, - "delete": { + } + }, + "/api/v1/monitors/{id}/resume": { + "post": { "tags": [ "Monitors" ], - "summary": "Remove tags from a monitor by their IDs", - "operationId": "removeMonitorTags", + "summary": "Resume a monitor (set enabled=true)", + "operationId": "resume", "parameters": [ { "name": "id", @@ -7966,20 +8236,17 @@ } } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RemoveMonitorTagsRequest" + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/SingleValueResponseMonitorDto" + } } } }, - "required": true - }, - "responses": { - "204": { - "description": "No Content" - }, "400": { "description": "Bad request — the payload failed validation", "content": { @@ -8063,14 +8330,14 @@ } } }, - "/api/v1/monitors/{id}/test": { + "/api/v1/monitors/{id}/rotate-token": { "post": { "tags": [ "Monitors" ], - "summary": "Test an existing monitor", - "description": "Runs the saved config and assertions of an existing monitor once, without persisting any result. Runs synchronously and returns the same shape as the ad-hoc test.", - "operationId": "testExisting", + "summary": "Rotate the ping token for a heartbeat monitor", + "description": "Generates a new ping token. The old token remains valid for 24 hours to allow cron jobs to be updated without downtime. Only supported for HEARTBEAT monitors.", + "operationId": "rotateToken", "parameters": [ { "name": "id", @@ -8088,7 +8355,7 @@ "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseMonitorTestResultDto" + "$ref": "#/components/schemas/SingleValueResponseMonitorDto" } } } @@ -8176,142 +8443,14 @@ } } }, - "/api/v1/monitors/{id}/uptime": { - "get": { - "tags": [ - "Check Results" - ], - "summary": "Get uptime statistics", - "description": "Returns uptime percentage and latency statistics for the requested time window, computed from continuous aggregates. Uses hourly aggregates for 24h/7d windows and daily aggregates for 30d/90d windows.", - "operationId": "getUptime", - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "string", - "format": "uuid" - } - }, - { - "name": "window", - "in": "query", - "description": "Time window for uptime calculation", - "required": false, - "schema": { - "type": "string", - "enum": [ - "24h", - "7d", - "30d", - "90d" - ] - } - } - ], - "responses": { - "200": { - "description": "Uptime statistics", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/UptimeDto" - } - } - } - }, - "400": { - "description": "Invalid window parameter", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/SingleValueResponseUptimeDto" - } - } - } - }, - "401": { - "description": "Unauthorized — missing or invalid credentials", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "403": { - "description": "Monitor does not belong to the caller's org", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/SingleValueResponseUptimeDto" - } - } - } - }, - "404": { - "description": "Monitor not found", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/SingleValueResponseUptimeDto" - } - } - } - }, - "409": { - "description": "Conflict — the request collides with current resource state", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "500": { - "description": "Internal server error — see the message field for details", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "502": { - "description": "Bad gateway — an upstream provider returned an error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "503": { - "description": "Service unavailable — try again shortly", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - } - } - } - }, - "/api/v1/monitors/{id}/versions": { + "/api/v1/monitors/{id}/status-pages": { "get": { "tags": [ "Monitors" ], - "summary": "List version history for a monitor", - "description": "Returns a paginated list of mutation snapshots for the monitor, newest first. Each version captures the full monitor config at the time of a PUT /monitors/{id} call.", - "operationId": "listVersions", + "summary": "List status pages that contain this monitor as a component", + "description": "Returns all status pages where this monitor appears as a component, enabling the detail page to show 'Appears On' cross-links.", + "operationId": "listStatusPagesForMonitor", "parameters": [ { "name": "id", @@ -8321,14 +8460,6 @@ "type": "string", "format": "uuid" } - }, - { - "name": "pageable", - "in": "query", - "required": true, - "schema": { - "$ref": "#/components/schemas/Pageable" - } } ], "responses": { @@ -8337,7 +8468,7 @@ "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/TableValueResultMonitorVersionDto" + "$ref": "#/components/schemas/TableValueResultStatusPageDto" } } } @@ -8425,14 +8556,13 @@ } } }, - "/api/v1/monitors/{id}/versions/{version}": { + "/api/v1/monitors/{id}/tags": { "get": { "tags": [ "Monitors" ], - "summary": "Get a specific version snapshot for a monitor", - "description": "Returns the full monitor config snapshot captured at the given version number.", - "operationId": "getVersion", + "summary": "Get all tags applied to a monitor", + "operationId": "getMonitorTags", "parameters": [ { "name": "id", @@ -8442,15 +8572,6 @@ "type": "string", "format": "uuid" } - }, - { - "name": "version", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } } ], "responses": { @@ -8459,7 +8580,7 @@ "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseMonitorVersionDto" + "$ref": "#/components/schemas/TableValueResultTagDto" } } } @@ -8545,18 +8666,16 @@ } } } - } - }, - "/api/v1/monitors/{monitorId}/alert-channels": { - "put": { + }, + "post": { "tags": [ - "Monitor Alert Channels" + "Monitors" ], - "summary": "Replace the linked alert channel set for a monitor", - "operationId": "setChannels", + "summary": "Add tags to a monitor; supports existing tag IDs and inline creation of new tags", + "operationId": "addMonitorTags", "parameters": [ { - "name": "monitorId", + "name": "id", "in": "path", "required": true, "schema": { @@ -8569,7 +8688,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SetAlertChannelsRequest" + "$ref": "#/components/schemas/AddMonitorTagsRequest" } } }, @@ -8581,7 +8700,7 @@ "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseListUUID" + "$ref": "#/components/schemas/TableValueResultTagDto" } } } @@ -8667,18 +8786,16 @@ } } } - } - }, - "/api/v1/monitors/{monitorId}/assertions": { - "post": { + }, + "delete": { "tags": [ - "Monitor Assertions" + "Monitors" ], - "summary": "Add an assertion to a monitor", - "operationId": "add", + "summary": "Remove tags from a monitor by their IDs", + "operationId": "removeMonitorTags", "parameters": [ { - "name": "monitorId", + "name": "id", "in": "path", "required": true, "schema": { @@ -8691,22 +8808,15 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/CreateAssertionRequest" + "$ref": "#/components/schemas/RemoveMonitorTagsRequest" } } }, "required": true }, "responses": { - "201": { - "description": "Created", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/SingleValueResponseMonitorAssertionDto" - } - } - } + "204": { + "description": "No Content" }, "400": { "description": "Bad request — the payload failed validation", @@ -8791,25 +8901,17 @@ } } }, - "/api/v1/monitors/{monitorId}/assertions/{assertionId}": { - "put": { + "/api/v1/monitors/{id}/test": { + "post": { "tags": [ - "Monitor Assertions" + "Monitors" ], - "summary": "Update an assertion on a monitor", - "operationId": "update_10", + "summary": "Test an existing monitor", + "description": "Runs the saved config and assertions of an existing monitor once, without persisting any result. Runs synchronously and returns the same shape as the ad-hoc test. MULTI_STEP_API and BROWSER are rejected with MONITOR_CODE_CHECK_TEST_UNAVAILABLE until fleet dry-run is available.", + "operationId": "testExisting", "parameters": [ { - "name": "monitorId", - "in": "path", - "required": true, - "schema": { - "type": "string", - "format": "uuid" - } - }, - { - "name": "assertionId", + "name": "id", "in": "path", "required": true, "schema": { @@ -8818,138 +8920,16 @@ } } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateAssertionRequest" - } - } - }, - "required": true - }, "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseMonitorAssertionDto" - } - } - } - }, - "400": { - "description": "Bad request — the payload failed validation", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "401": { - "description": "Unauthorized — missing or invalid credentials", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "403": { - "description": "Forbidden — the actor lacks permission for this resource", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "404": { - "description": "Not found — the requested resource does not exist", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "409": { - "description": "Conflict — the request collides with current resource state", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "500": { - "description": "Internal server error — see the message field for details", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "502": { - "description": "Bad gateway — an upstream provider returned an error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "503": { - "description": "Service unavailable — try again shortly", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/SingleValueResponseMonitorTestResultDto" } } } - } - } - }, - "delete": { - "tags": [ - "Monitor Assertions" - ], - "summary": "Remove an assertion from a monitor", - "operationId": "remove_1", - "parameters": [ - { - "name": "monitorId", - "in": "path", - "required": true, - "schema": { - "type": "string", - "format": "uuid" - } - }, - { - "name": "assertionId", - "in": "path", - "required": true, - "schema": { - "type": "string", - "format": "uuid" - } - } - ], - "responses": { - "204": { - "description": "No Content" }, "400": { "description": "Bad request — the payload failed validation", @@ -9034,16 +9014,17 @@ } } }, - "/api/v1/monitors/{monitorId}/auth": { - "put": { + "/api/v1/monitors/{id}/test-notifications": { + "post": { "tags": [ - "Monitor Auth" + "Monitors" ], - "summary": "Update authentication config for a monitor", - "operationId": "update_9", + "summary": "Send test notifications through the monitor's alert channels", + "description": "Sends a test alert to all specified channel IDs (must be channels attached to this monitor). If no channelIds are provided, tests all attached channels. Returns per-channel results.", + "operationId": "testNotifications", "parameters": [ { - "name": "monitorId", + "name": "id", "in": "path", "required": true, "schema": { @@ -9056,7 +9037,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/UpdateMonitorAuthRequest" + "$ref": "#/components/schemas/TestMonitorNotificationsRequest" } } }, @@ -9068,7 +9049,7 @@ "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseMonitorAuthDto" + "$ref": "#/components/schemas/TableValueResultTestChannelResult" } } } @@ -9154,51 +9135,59 @@ } } } - }, - "post": { + } + }, + "/api/v1/monitors/{id}/uptime": { + "get": { "tags": [ - "Monitor Auth" + "Check Results" ], - "summary": "Set authentication config for a monitor", - "operationId": "set", + "summary": "Get uptime statistics", + "description": "Returns uptime percentage and latency statistics for the requested time window, computed from continuous aggregates. Uses hourly aggregates for 24h/7d windows and daily aggregates for 30d/90d windows.", + "operationId": "getUptime", "parameters": [ { - "name": "monitorId", + "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } + }, + { + "name": "window", + "in": "query", + "description": "Time window for uptime calculation", + "required": false, + "schema": { + "type": "string", + "enum": [ + "24h", + "7d", + "30d", + "90d" + ] + } } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SetMonitorAuthRequest" - } - } - }, - "required": true - }, "responses": { - "201": { - "description": "Created", + "200": { + "description": "Uptime statistics", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseMonitorAuthDto" + "$ref": "#/components/schemas/UptimeDto" } } } }, "400": { - "description": "Bad request — the payload failed validation", + "description": "Invalid window parameter", "content": { - "application/json": { + "*/*": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/SingleValueResponseUptimeDto" } } } @@ -9214,21 +9203,21 @@ } }, "403": { - "description": "Forbidden — the actor lacks permission for this resource", + "description": "Monitor does not belong to the caller's org", "content": { - "application/json": { + "*/*": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/SingleValueResponseUptimeDto" } } } }, "404": { - "description": "Not found — the requested resource does not exist", + "description": "Monitor not found", "content": { - "application/json": { + "*/*": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/SingleValueResponseUptimeDto" } } } @@ -9274,27 +9263,45 @@ } } } - }, - "delete": { + } + }, + "/api/v1/monitors/{id}/versions": { + "get": { "tags": [ - "Monitor Auth" + "Monitors" ], - "summary": "Remove authentication config from a monitor", - "operationId": "remove", + "summary": "List version history for a monitor", + "description": "Returns a paginated list of mutation snapshots for the monitor, newest first. Each version captures the full monitor config at the time of a PUT /monitors/{id} call.", + "operationId": "listVersions", "parameters": [ { - "name": "monitorId", + "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } + }, + { + "name": "pageable", + "in": "query", + "required": true, + "schema": { + "$ref": "#/components/schemas/Pageable" + } } ], "responses": { - "204": { - "description": "No Content" + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/TableValueResultMonitorVersionDto" + } + } + } }, "400": { "description": "Bad request — the payload failed validation", @@ -9379,33 +9386,41 @@ } } }, - "/api/v1/monitors/{monitorId}/policy": { + "/api/v1/monitors/{id}/versions/{version}": { "get": { "tags": [ - "Incident Policies" + "Monitors" ], - "summary": "Get incident policy for a monitor", - "description": "Returns the trigger rules, confirmation settings, and recovery settings for the given monitor.", - "operationId": "get_5", + "summary": "Get a specific version snapshot for a monitor", + "description": "Returns the full monitor config snapshot captured at the given version number.", + "operationId": "getVersion", "parameters": [ { - "name": "monitorId", + "name": "id", "in": "path", - "description": "Monitor UUID", "required": true, "schema": { "type": "string", "format": "uuid" } + }, + { + "name": "version", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } } ], "responses": { "200": { - "description": "Policy found", + "description": "OK", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/IncidentPolicyDto" + "$ref": "#/components/schemas/SingleValueResponseMonitorVersionDto" } } } @@ -9441,11 +9456,11 @@ } }, "404": { - "description": "Monitor or policy not found", + "description": "Not found — the requested resource does not exist", "content": { - "*/*": { + "application/json": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseIncidentPolicyDto" + "$ref": "#/components/schemas/ErrorResponse" } } } @@ -9491,19 +9506,19 @@ } } } - }, + } + }, + "/api/v1/monitors/{monitorId}/alert-channels": { "put": { "tags": [ - "Incident Policies" + "Monitor Alert Channels" ], - "summary": "Update incident policy for a monitor", - "description": "Replaces the trigger rules, confirmation settings, and recovery settings. All fields are validated before saving.", - "operationId": "update_8", + "summary": "Replace the linked alert channel set for a monitor", + "operationId": "setChannels", "parameters": [ { "name": "monitorId", "in": "path", - "description": "Monitor UUID", "required": true, "schema": { "type": "string", @@ -9515,119 +9530,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/UpdateIncidentPolicyRequest" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "Policy updated", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/IncidentPolicyDto" - } - } - } - }, - "400": { - "description": "Validation error in JSONB shape", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/SingleValueResponseIncidentPolicyDto" - } - } - } - }, - "401": { - "description": "Unauthorized — missing or invalid credentials", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "403": { - "description": "Forbidden — the actor lacks permission for this resource", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "404": { - "description": "Monitor or policy not found", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/SingleValueResponseIncidentPolicyDto" - } - } - } - }, - "409": { - "description": "Conflict — the request collides with current resource state", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "500": { - "description": "Internal server error — see the message field for details", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "502": { - "description": "Bad gateway — an upstream provider returned an error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "503": { - "description": "Service unavailable — try again shortly", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - } - } - } - }, - "/api/v1/monitors/bulk": { - "post": { - "tags": [ - "Monitors" - ], - "summary": "Bulk action on monitors", - "description": "Applies PAUSE, RESUME, DELETE, ADD_TAG, or REMOVE_TAG to a list of monitors. Returns a partial-success response indicating which monitors succeeded and which failed.", - "operationId": "bulkAction", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/BulkMonitorActionRequest" + "$ref": "#/components/schemas/SetAlertChannelsRequest" } } }, @@ -9639,7 +9542,7 @@ "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseBulkMonitorActionResult" + "$ref": "#/components/schemas/SingleValueResponseListUUID" } } } @@ -9727,31 +9630,41 @@ } } }, - "/api/v1/monitors/test": { + "/api/v1/monitors/{monitorId}/assertions": { "post": { "tags": [ - "Monitors" + "Monitor Assertions" + ], + "summary": "Add an assertion to a monitor", + "operationId": "add", + "parameters": [ + { + "name": "monitorId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } ], - "summary": "Ad-hoc monitor test", - "description": "Executes a one-off check from an inline config without saving the monitor. Runs synchronously and returns status code, response time, assertion results, body preview, and headers.", - "operationId": "testAdHoc", "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/MonitorTestRequest" + "$ref": "#/components/schemas/CreateAssertionRequest" } } }, "required": true }, "responses": { - "200": { - "description": "OK", + "201": { + "description": "Created", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseMonitorTestResultDto" + "$ref": "#/components/schemas/SingleValueResponseMonitorAssertionDto" } } } @@ -9839,19 +9752,26 @@ } } }, - "/api/v1/notification-dispatches": { - "get": { + "/api/v1/monitors/{monitorId}/assertions/{assertionId}": { + "put": { "tags": [ - "Notification Dispatches" + "Monitor Assertions" ], - "summary": "List all dispatches for an incident", - "description": "Returns all notification dispatches for the given incident that belong to the authenticated org's policies. Each dispatch includes delivery records for all associated channels.", - "operationId": "listByIncident", + "summary": "Update an assertion on a monitor", + "operationId": "update_10", "parameters": [ { - "name": "incident_id", - "in": "query", - "description": "UUID of the incident to inspect", + "name": "monitorId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "assertionId", + "in": "path", "required": true, "schema": { "type": "string", @@ -9859,13 +9779,23 @@ } } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateAssertionRequest" + } + } + }, + "required": true + }, "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/TableValueResultNotificationDispatchDto" + "$ref": "#/components/schemas/SingleValueResponseMonitorAssertionDto" } } } @@ -9951,19 +9881,25 @@ } } } - } - }, - "/api/v1/notification-dispatches/{id}": { - "get": { + }, + "delete": { "tags": [ - "Notification Dispatches" + "Monitor Assertions" ], - "summary": "Get a single dispatch with full escalation and delivery history", - "description": "Returns the dispatch state including current escalation step, acknowledgment info, and all delivery attempts made across every step.", - "operationId": "getById_3", + "summary": "Remove an assertion from a monitor", + "operationId": "remove_1", "parameters": [ { - "name": "id", + "name": "monitorId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "assertionId", "in": "path", "required": true, "schema": { @@ -9973,15 +9909,8 @@ } ], "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/SingleValueResponseNotificationDispatchDto" - } - } - } + "204": { + "description": "No Content" }, "400": { "description": "Bad request — the payload failed validation", @@ -10066,17 +9995,16 @@ } } }, - "/api/v1/notification-dispatches/{id}/acknowledge": { - "post": { + "/api/v1/monitors/{monitorId}/auth": { + "put": { "tags": [ - "Notification Dispatches" + "Monitor Auth" ], - "summary": "Acknowledge a notification dispatch", - "description": "Marks the dispatch as acknowledged. The dispatch must be in DELIVERED or ESCALATING state. Sets acknowledgedAt, acknowledgedBy (actor email), and acknowledgedVia (DASHBOARD).", - "operationId": "acknowledge", + "summary": "Update authentication config for a monitor", + "operationId": "update_9", "parameters": [ { - "name": "id", + "name": "monitorId", "in": "path", "required": true, "schema": { @@ -10085,13 +10013,23 @@ } } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateMonitorAuthRequest" + } + } + }, + "required": true + }, "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseNotificationDispatchDto" + "$ref": "#/components/schemas/SingleValueResponseMonitorAuthDto" } } } @@ -10177,22 +10115,41 @@ } } } - } - }, - "/api/v1/notification-policies": { - "get": { + }, + "post": { "tags": [ - "Notification Policies" + "Monitor Auth" ], - "summary": "List all notification policies for the authenticated org", - "operationId": "list_7", + "summary": "Set authentication config for a monitor", + "operationId": "set", + "parameters": [ + { + "name": "monitorId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetMonitorAuthRequest" + } + } + }, + "required": true + }, "responses": { - "200": { - "description": "OK", + "201": { + "description": "Created", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/TableValueResultNotificationPolicyDto" + "$ref": "#/components/schemas/SingleValueResponseMonitorAuthDto" } } } @@ -10279,32 +10236,26 @@ } } }, - "post": { + "delete": { "tags": [ - "Notification Policies" + "Monitor Auth" ], - "summary": "Create a notification policy with match rules and escalation chain", - "operationId": "create_8", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateNotificationPolicyRequest" - } + "summary": "Remove authentication config from a monitor", + "operationId": "remove", + "parameters": [ + { + "name": "monitorId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" } - }, - "required": true - }, + } + ], "responses": { - "201": { - "description": "Created", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/SingleValueResponseNotificationPolicyDto" - } - } - } + "204": { + "description": "No Content" }, "400": { "description": "Bad request — the payload failed validation", @@ -10389,17 +10340,19 @@ } } }, - "/api/v1/notification-policies/{id}": { + "/api/v1/monitors/{monitorId}/policy": { "get": { "tags": [ - "Notification Policies" + "Incident Policies" ], - "summary": "Get a notification policy by ID", - "operationId": "getById_1", + "summary": "Get incident policy for a monitor", + "description": "Returns the trigger rules, confirmation settings, and recovery settings for the given monitor.", + "operationId": "get_5", "parameters": [ { - "name": "id", + "name": "monitorId", "in": "path", + "description": "Monitor UUID", "required": true, "schema": { "type": "string", @@ -10409,11 +10362,11 @@ ], "responses": { "200": { - "description": "OK", + "description": "Policy found", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseNotificationPolicyDto" + "$ref": "#/components/schemas/IncidentPolicyDto" } } } @@ -10449,11 +10402,11 @@ } }, "404": { - "description": "Not found — the requested resource does not exist", + "description": "Monitor or policy not found", "content": { - "application/json": { + "*/*": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/SingleValueResponseIncidentPolicyDto" } } } @@ -10502,14 +10455,16 @@ }, "put": { "tags": [ - "Notification Policies" + "Incident Policies" ], - "summary": "Update a notification policy", - "operationId": "update_7", + "summary": "Update incident policy for a monitor", + "description": "Replaces the trigger rules, confirmation settings, and recovery settings. All fields are validated before saving.", + "operationId": "update_8", "parameters": [ { - "name": "id", + "name": "monitorId", "in": "path", + "description": "Monitor UUID", "required": true, "schema": { "type": "string", @@ -10521,7 +10476,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/UpdateNotificationPolicyRequest" + "$ref": "#/components/schemas/UpdateIncidentPolicyRequest" } } }, @@ -10529,21 +10484,21 @@ }, "responses": { "200": { - "description": "OK", + "description": "Policy updated", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseNotificationPolicyDto" + "$ref": "#/components/schemas/IncidentPolicyDto" } } } }, "400": { - "description": "Bad request — the payload failed validation", + "description": "Validation error in JSONB shape", "content": { - "application/json": { + "*/*": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/SingleValueResponseIncidentPolicyDto" } } } @@ -10569,11 +10524,11 @@ } }, "404": { - "description": "Not found — the requested resource does not exist", + "description": "Monitor or policy not found", "content": { - "application/json": { + "*/*": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/SingleValueResponseIncidentPolicyDto" } } } @@ -10619,27 +10574,36 @@ } } } - }, - "delete": { + } + }, + "/api/v1/monitors/bulk": { + "post": { "tags": [ - "Notification Policies" + "Monitors" ], - "summary": "Delete a notification policy", - "operationId": "delete_6", - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "string", - "format": "uuid" + "summary": "Bulk action on monitors", + "description": "Applies PAUSE, RESUME, DELETE, ADD_TAG, or REMOVE_TAG to a list of monitors. Returns a partial-success response indicating which monitors succeeded and which failed.", + "operationId": "bulkAction", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BulkMonitorActionRequest" + } } - } - ], + }, + "required": true + }, "responses": { - "204": { - "description": "No Content" + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/SingleValueResponseBulkMonitorActionResult" + } + } + } }, "400": { "description": "Bad request — the payload failed validation", @@ -10724,31 +10688,31 @@ } } }, - "/api/v1/notification-policies/{id}/dispatches": { - "get": { + "/api/v1/monitors/test": { + "post": { "tags": [ - "Notification Policies" + "Monitors" ], - "summary": "List all dispatches (firing history) for a notification policy", - "operationId": "listDispatches", - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "string", - "format": "uuid" + "summary": "Ad-hoc monitor test", + "description": "Executes a one-off check from an inline config without saving the monitor. Runs synchronously and returns status code, response time, assertion results, body preview, and headers. MULTI_STEP_API and BROWSER are rejected with MONITOR_CODE_CHECK_TEST_UNAVAILABLE until fleet dry-run is available.", + "operationId": "testAdHoc", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MonitorTestRequest" + } } - } - ], + }, + "required": true + }, "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/TableValueResultNotificationDispatchDto" + "$ref": "#/components/schemas/SingleValueResponseMonitorTestResultDto" } } } @@ -10836,17 +10800,19 @@ } } }, - "/api/v1/notification-policies/{id}/test": { - "post": { + "/api/v1/notification-dispatches": { + "get": { "tags": [ - "Notification Policies" + "Notification Dispatches" ], - "summary": "Dry-run: evaluate a policy's match rules against a supplied incident context", - "operationId": "test_1", + "summary": "List all dispatches for an incident", + "description": "Returns all notification dispatches for the given incident that belong to the authenticated org's policies. Each dispatch includes delivery records for all associated channels.", + "operationId": "listByIncident", "parameters": [ { - "name": "id", - "in": "path", + "name": "incident_id", + "in": "query", + "description": "UUID of the incident to inspect", "required": true, "schema": { "type": "string", @@ -10854,22 +10820,13 @@ } } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TestNotificationPolicyRequest" - } - } - } - }, "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseTestMatchResult" + "$ref": "#/components/schemas/TableValueResultNotificationDispatchDto" } } } @@ -10957,41 +10914,135 @@ } } }, - "/api/v1/notifications": { + "/api/v1/notification-dispatches/{id}": { "get": { "tags": [ - "Notifications" + "Notification Dispatches" ], - "summary": "List notifications for the current user", - "operationId": "list_16", + "summary": "Get a single dispatch with full escalation and delivery history", + "description": "Returns the dispatch state including current escalation step, acknowledgment info, and all delivery attempts made across every step.", + "operationId": "getById_3", "parameters": [ { - "name": "unreadOnly", - "in": "query", - "required": false, + "name": "id", + "in": "path", + "required": true, "schema": { - "type": "boolean", - "default": false + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/SingleValueResponseNotificationDispatchDto" + } + } } }, - { - "name": "page", - "in": "query", - "required": false, - "schema": { - "type": "integer", - "format": "int32", - "default": 0 + "400": { + "description": "Bad request — the payload failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } } }, + "401": { + "description": "Unauthorized — missing or invalid credentials", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden — the actor lacks permission for this resource", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Not found — the requested resource does not exist", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict — the request collides with current resource state", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error — see the message field for details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "502": { + "description": "Bad gateway — an upstream provider returned an error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "503": { + "description": "Service unavailable — try again shortly", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/api/v1/notification-dispatches/{id}/acknowledge": { + "post": { + "tags": [ + "Notification Dispatches" + ], + "summary": "Acknowledge a notification dispatch", + "description": "Marks the dispatch as acknowledged. The dispatch must be in DELIVERED or ESCALATING state. Sets acknowledgedAt, acknowledgedBy (actor email), and acknowledgedVia (DASHBOARD).", + "operationId": "acknowledge", + "parameters": [ { - "name": "size", - "in": "query", - "required": false, + "name": "id", + "in": "path", + "required": true, "schema": { - "type": "integer", - "format": "int32", - "default": 20 + "type": "string", + "format": "uuid" } } ], @@ -11001,7 +11052,7 @@ "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/TableValueResultNotificationDto" + "$ref": "#/components/schemas/SingleValueResponseNotificationDispatchDto" } } } @@ -11089,27 +11140,35 @@ } } }, - "/api/v1/notifications/{id}/read": { - "put": { + "/api/v1/notification-dispatches/{id}/unacknowledge": { + "post": { "tags": [ - "Notifications" + "Notification Dispatches" ], - "summary": "Mark a notification as read", - "operationId": "markRead", + "summary": "Unacknowledge a notification dispatch", + "description": "Reverses a mistaken acknowledgment without reopening the incident. Allowed only from ACKNOWLEDGED. Clears ack fields, stays on the current escalation step, restores nextEscalationAt, and resumes escalation (ESCALATING if more steps remain, else DELIVERED). MEMBER+.", + "operationId": "unacknowledge", "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { - "type": "integer", - "format": "int64" + "type": "string", + "format": "uuid" } } ], "responses": { - "204": { - "description": "No Content" + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/SingleValueResponseNotificationDispatchDto" + } + } + } }, "400": { "description": "Bad request — the payload failed validation", @@ -11194,16 +11253,23 @@ } } }, - "/api/v1/notifications/read-all": { - "put": { + "/api/v1/notification-policies": { + "get": { "tags": [ - "Notifications" + "Notification Policies" ], - "summary": "Mark all notifications as read", - "operationId": "markAllRead", + "summary": "List all notification policies for the authenticated org", + "operationId": "list_7", "responses": { - "204": { - "description": "No Content" + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/TableValueResultNotificationPolicyDto" + } + } + } }, "400": { "description": "Bad request — the payload failed validation", @@ -11286,22 +11352,30 @@ } } } - } - }, - "/api/v1/notifications/unread-count": { - "get": { + }, + "post": { "tags": [ - "Notifications" + "Notification Policies" ], - "summary": "Get unread notification count", - "operationId": "unreadCount", + "summary": "Create a notification policy with match rules and escalation chain", + "operationId": "create_8", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateNotificationPolicyRequest" + } + } + }, + "required": true + }, "responses": { - "200": { - "description": "OK", + "201": { + "description": "Created", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseLong" + "$ref": "#/components/schemas/SingleValueResponseNotificationPolicyDto" } } } @@ -11389,20 +11463,31 @@ } } }, - "/api/v1/org": { + "/api/v1/notification-policies/{id}": { "get": { "tags": [ - "Organizations" + "Notification Policies" + ], + "summary": "Get a notification policy by ID", + "operationId": "getById_1", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } ], - "summary": "Get the current organization", - "operationId": "get_4", "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseOrganizationDto" + "$ref": "#/components/schemas/SingleValueResponseNotificationPolicyDto" } } } @@ -11491,15 +11576,26 @@ }, "put": { "tags": [ - "Organizations" + "Notification Policies" + ], + "summary": "Update a notification policy", + "operationId": "update_7", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } ], - "summary": "Update the current organization", - "operationId": "update_6", "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/UpdateOrgDetailsRequest" + "$ref": "#/components/schemas/UpdateNotificationPolicyRequest" } } }, @@ -11511,7 +11607,7 @@ "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseOrganizationDto" + "$ref": "#/components/schemas/SingleValueResponseNotificationPolicyDto" } } } @@ -11597,25 +11693,27 @@ } } } - } - }, - "/api/v1/resource-groups": { - "get": { + }, + "delete": { "tags": [ - "Resource Groups" + "Notification Policies" ], - "summary": "List all resource groups for the authenticated org with health summaries", - "operationId": "list_6", - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/TableValueResultResourceGroupDto" - } - } + "summary": "Delete a notification policy", + "operationId": "delete_6", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" } + } + ], + "responses": { + "204": { + "description": "No Content" }, "400": { "description": "Bad request — the payload failed validation", @@ -11698,30 +11796,33 @@ } } } - }, - "post": { + } + }, + "/api/v1/notification-policies/{id}/dispatches": { + "get": { "tags": [ - "Resource Groups" + "Notification Policies" ], - "summary": "Create a new resource group", - "operationId": "create_7", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateResourceGroupRequest" - } + "summary": "List all dispatches (firing history) for a notification policy", + "operationId": "listDispatches", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" } - }, - "required": true - }, + } + ], "responses": { - "201": { - "description": "Created", + "200": { + "description": "OK", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseResourceGroupDto" + "$ref": "#/components/schemas/TableValueResultNotificationDispatchDto" } } } @@ -11809,14 +11910,13 @@ } } }, - "/api/v1/resource-groups/{id}": { - "get": { + "/api/v1/notification-policies/{id}/test": { + "post": { "tags": [ - "Resource Groups" + "Notification Policies" ], - "summary": "Get a resource group by id with member statuses and inherited settings", - "description": "Pass includeMetrics=true to enrich each member with 24h uptime, chart data, and latency metrics.", - "operationId": "get_3", + "summary": "Dry-run: evaluate a policy's match rules against a supplied incident context", + "operationId": "test_1", "parameters": [ { "name": "id", @@ -11826,24 +11926,24 @@ "type": "string", "format": "uuid" } - }, - { - "name": "includeMetrics", - "in": "query", - "required": false, - "schema": { - "type": "boolean", - "default": false - } } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TestNotificationPolicyRequest" + } + } + } + }, "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseResourceGroupDto" + "$ref": "#/components/schemas/SingleValueResponseTestMatchResult" } } } @@ -11929,41 +12029,53 @@ } } } - }, - "put": { + } + }, + "/api/v1/notifications": { + "get": { "tags": [ - "Resource Groups" + "Notifications" ], - "summary": "Update a resource group's name, description, alert policy, inherited settings, and health threshold", - "operationId": "update_5", + "summary": "List notifications for the current user", + "operationId": "list_17", "parameters": [ { - "name": "id", - "in": "path", - "required": true, + "name": "unreadOnly", + "in": "query", + "required": false, "schema": { - "type": "string", - "format": "uuid" + "type": "boolean", + "default": false } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateResourceGroupRequest" - } + }, + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "format": "int32", + "default": 0 } }, - "required": true - }, + { + "name": "size", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "format": "int32", + "default": 20 + } + } + ], "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseResourceGroupDto" + "$ref": "#/components/schemas/TableValueResultNotificationDto" } } } @@ -12049,21 +12161,23 @@ } } } - }, - "delete": { + } + }, + "/api/v1/notifications/{id}/read": { + "put": { "tags": [ - "Resource Groups" + "Notifications" ], - "summary": "Delete a resource group (cascades to member rows)", - "operationId": "delete_5", + "summary": "Mark a notification as read", + "operationId": "markRead", "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { - "type": "string", - "format": "uuid" + "type": "integer", + "format": "int64" } } ], @@ -12154,35 +12268,16 @@ } } }, - "/api/v1/resource-groups/{id}/health": { - "get": { + "/api/v1/notifications/read-all": { + "put": { "tags": [ - "Resource Groups" - ], - "summary": "Get the detailed health breakdown for a resource group", - "description": "Returns member counts, worst-of status, and threshold-based health evaluation. The thresholdStatus field is populated only when a health threshold is configured.", - "operationId": "getHealth", - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "string", - "format": "uuid" - } - } + "Notifications" ], + "summary": "Mark all notifications as read", + "operationId": "markAllRead", "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/SingleValueResponseResourceGroupHealthDto" - } - } - } + "204": { + "description": "No Content" }, "400": { "description": "Bad request — the payload failed validation", @@ -12267,41 +12362,20 @@ } } }, - "/api/v1/resource-groups/{id}/members": { - "post": { + "/api/v1/notifications/unread-count": { + "get": { "tags": [ - "Resource Groups" - ], - "summary": "Add a monitor or service member to a resource group", - "operationId": "addMember_1", - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "string", - "format": "uuid" - } - } + "Notifications" ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AddResourceGroupMemberRequest" - } - } - }, - "required": true - }, + "summary": "Get unread notification count", + "operationId": "unreadCount", "responses": { - "201": { - "description": "Created", + "200": { + "description": "OK", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseResourceGroupMemberDto" + "$ref": "#/components/schemas/SingleValueResponseLong" } } } @@ -12389,36 +12463,23 @@ } } }, - "/api/v1/resource-groups/{id}/members/{memberId}": { - "delete": { + "/api/v1/org": { + "get": { "tags": [ - "Resource Groups" - ], - "summary": "Remove a member from a resource group", - "operationId": "removeMember_1", - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "string", - "format": "uuid" - } - }, - { - "name": "memberId", - "in": "path", - "required": true, - "schema": { - "type": "string", - "format": "uuid" - } - } + "Organizations" ], + "summary": "Get the current organization", + "operationId": "get_4", "responses": { - "204": { - "description": "No Content" + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/SingleValueResponseOrganizationDto" + } + } + } }, "400": { "description": "Bad request — the payload failed validation", @@ -12501,22 +12562,30 @@ } } } - } - }, - "/api/v1/secrets": { - "get": { + }, + "put": { "tags": [ - "Secrets" + "Organizations" ], - "summary": "List secrets", - "operationId": "list_5", + "summary": "Update the current organization", + "operationId": "update_6", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateOrgDetailsRequest" + } + } + }, + "required": true + }, "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/TableValueResultSecretDto" + "$ref": "#/components/schemas/SingleValueResponseOrganizationDto" } } } @@ -12602,30 +12671,22 @@ } } } - }, - "post": { + } + }, + "/api/v1/resource-groups": { + "get": { "tags": [ - "Secrets" + "Resource Groups" ], - "summary": "Create secret", - "operationId": "create_6", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateSecretRequest" - } - } - }, - "required": true - }, + "summary": "List all resource groups for the authenticated org with health summaries", + "operationId": "list_6", "responses": { - "201": { - "description": "Created", + "200": { + "description": "OK", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseSecretDto" + "$ref": "#/components/schemas/TableValueResultResourceGroupDto" } } } @@ -12711,42 +12772,30 @@ } } } - } - }, - "/api/v1/secrets/{key}": { - "put": { + }, + "post": { "tags": [ - "Secrets" - ], - "summary": "Update secret", - "operationId": "update_4", - "parameters": [ - { - "name": "key", - "in": "path", - "required": true, - "schema": { - "type": "string" - } - } + "Resource Groups" ], + "summary": "Create a new resource group", + "operationId": "create_7", "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/UpdateSecretRequest" + "$ref": "#/components/schemas/CreateResourceGroupRequest" } } }, "required": true }, "responses": { - "200": { - "description": "OK", + "201": { + "description": "Created", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseSecretDto" + "$ref": "#/components/schemas/SingleValueResponseResourceGroupDto" } } } @@ -12832,26 +12881,46 @@ } } } - }, - "delete": { + } + }, + "/api/v1/resource-groups/{id}": { + "get": { "tags": [ - "Secrets" + "Resource Groups" ], - "summary": "Delete secret", - "operationId": "delete_4", + "summary": "Get a resource group by id with member statuses and inherited settings", + "description": "Pass includeMetrics=true to enrich each member with 24h uptime, chart data, and latency metrics.", + "operationId": "get_3", "parameters": [ { - "name": "key", + "name": "id", "in": "path", "required": true, "schema": { - "type": "string" + "type": "string", + "format": "uuid" + } + }, + { + "name": "includeMetrics", + "in": "query", + "required": false, + "schema": { + "type": "boolean", + "default": false } } ], "responses": { - "204": { - "description": "No Content" + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/SingleValueResponseResourceGroupDto" + } + } + } }, "400": { "description": "Bad request — the payload failed validation", @@ -12934,22 +13003,41 @@ } } } - } - }, - "/api/v1/service-subscriptions": { - "get": { + }, + "put": { "tags": [ - "Service Subscriptions" + "Resource Groups" ], - "summary": "List all service subscriptions for the organization", - "operationId": "list_15", + "summary": "Update a resource group's name, description, alert policy, inherited settings, and health threshold", + "operationId": "update_5", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateResourceGroupRequest" + } + } + }, + "required": true + }, "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/TableValueResultServiceSubscriptionDto" + "$ref": "#/components/schemas/SingleValueResponseResourceGroupDto" } } } @@ -13035,15 +13123,13 @@ } } } - } - }, - "/api/v1/service-subscriptions/{id}": { - "get": { + }, + "delete": { "tags": [ - "Service Subscriptions" + "Resource Groups" ], - "summary": "Get a subscription by its ID", - "operationId": "get_10", + "summary": "Delete a resource group (cascades to member rows)", + "operationId": "delete_5", "parameters": [ { "name": "id", @@ -13056,15 +13142,8 @@ } ], "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/SingleValueResponseServiceSubscriptionDto" - } - } - } + "204": { + "description": "No Content" }, "400": { "description": "Bad request — the payload failed validation", @@ -13147,14 +13226,16 @@ } } } - }, - "delete": { + } + }, + "/api/v1/resource-groups/{id}/health": { + "get": { "tags": [ - "Service Subscriptions" + "Resource Groups" ], - "summary": "Remove a subscription by its ID", - "description": "Removes a specific subscription (whole-service or component-level). No-op if not found.", - "operationId": "unsubscribe_1", + "summary": "Get the detailed health breakdown for a resource group", + "description": "Returns member counts, worst-of status, and threshold-based health evaluation. The thresholdStatus field is populated only when a health threshold is configured.", + "operationId": "getHealth", "parameters": [ { "name": "id", @@ -13167,8 +13248,15 @@ } ], "responses": { - "204": { - "description": "No Content" + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/SingleValueResponseResourceGroupHealthDto" + } + } + } }, "400": { "description": "Bad request — the payload failed validation", @@ -13253,14 +13341,13 @@ } } }, - "/api/v1/service-subscriptions/{id}/alert-sensitivity": { - "patch": { + "/api/v1/resource-groups/{id}/members": { + "post": { "tags": [ - "Service Subscriptions" + "Resource Groups" ], - "summary": "Update alert sensitivity for a subscription", - "description": "Controls which external incidents trigger alerts and whether they page anyone: ALL (any status change, paged), INCIDENTS_ONLY (real vendor incidents, paged), MAJOR_ONLY (only DOWN-level incidents, paged), AWARENESS (real vendor incidents tracked silently — visible on the dashboard but no alert channels fire; default for new subscriptions).", - "operationId": "updateAlertSensitivity", + "summary": "Add a monitor or service member to a resource group", + "operationId": "addMember_1", "parameters": [ { "name": "id", @@ -13276,19 +13363,19 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/UpdateAlertSensitivityRequest" + "$ref": "#/components/schemas/AddResourceGroupMemberRequest" } } }, "required": true }, "responses": { - "200": { - "description": "OK", + "201": { + "description": "Created", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseServiceSubscriptionDto" + "$ref": "#/components/schemas/SingleValueResponseResourceGroupMemberDto" } } } @@ -13376,40 +13463,1912 @@ } } }, - "/api/v1/service-subscriptions/{slug}": { + "/api/v1/resource-groups/{id}/members/{memberId}": { + "delete": { + "tags": [ + "Resource Groups" + ], + "summary": "Remove a member from a resource group", + "operationId": "removeMember_1", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "memberId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "400": { + "description": "Bad request — the payload failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized — missing or invalid credentials", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden — the actor lacks permission for this resource", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Not found — the requested resource does not exist", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict — the request collides with current resource state", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error — see the message field for details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "502": { + "description": "Bad gateway — an upstream provider returned an error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "503": { + "description": "Service unavailable — try again shortly", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/api/v1/secrets": { + "get": { + "tags": [ + "Secrets" + ], + "summary": "List secrets", + "operationId": "list_5", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/TableValueResultSecretDto" + } + } + } + }, + "400": { + "description": "Bad request — the payload failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized — missing or invalid credentials", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden — the actor lacks permission for this resource", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Not found — the requested resource does not exist", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict — the request collides with current resource state", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error — see the message field for details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "502": { + "description": "Bad gateway — an upstream provider returned an error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "503": { + "description": "Service unavailable — try again shortly", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + }, "post": { "tags": [ - "Service Subscriptions" + "Secrets" + ], + "summary": "Create secret", + "operationId": "create_6", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateSecretRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Created", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/SingleValueResponseSecretDto" + } + } + } + }, + "400": { + "description": "Bad request — the payload failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized — missing or invalid credentials", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden — the actor lacks permission for this resource", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Not found — the requested resource does not exist", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict — the request collides with current resource state", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error — see the message field for details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "502": { + "description": "Bad gateway — an upstream provider returned an error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "503": { + "description": "Service unavailable — try again shortly", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/api/v1/secrets/{key}": { + "put": { + "tags": [ + "Secrets" + ], + "summary": "Update secret", + "operationId": "update_4", + "parameters": [ + { + "name": "key", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateSecretRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/SingleValueResponseSecretDto" + } + } + } + }, + "400": { + "description": "Bad request — the payload failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized — missing or invalid credentials", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden — the actor lacks permission for this resource", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Not found — the requested resource does not exist", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict — the request collides with current resource state", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error — see the message field for details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "502": { + "description": "Bad gateway — an upstream provider returned an error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "503": { + "description": "Service unavailable — try again shortly", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Secrets" + ], + "summary": "Delete secret", + "operationId": "delete_4", + "parameters": [ + { + "name": "key", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "400": { + "description": "Bad request — the payload failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized — missing or invalid credentials", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden — the actor lacks permission for this resource", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Not found — the requested resource does not exist", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict — the request collides with current resource state", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error — see the message field for details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "502": { + "description": "Bad gateway — an upstream provider returned an error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "503": { + "description": "Service unavailable — try again shortly", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/api/v1/service-subscriptions": { + "get": { + "tags": [ + "Service Subscriptions" + ], + "summary": "List all service subscriptions for the organization", + "operationId": "list_16", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/TableValueResultServiceSubscriptionDto" + } + } + } + }, + "400": { + "description": "Bad request — the payload failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized — missing or invalid credentials", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden — the actor lacks permission for this resource", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Not found — the requested resource does not exist", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict — the request collides with current resource state", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error — see the message field for details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "502": { + "description": "Bad gateway — an upstream provider returned an error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "503": { + "description": "Service unavailable — try again shortly", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/api/v1/service-subscriptions/{id}": { + "get": { + "tags": [ + "Service Subscriptions" + ], + "summary": "Get a subscription by its ID", + "operationId": "get_11", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/SingleValueResponseServiceSubscriptionDto" + } + } + } + }, + "400": { + "description": "Bad request — the payload failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized — missing or invalid credentials", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden — the actor lacks permission for this resource", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Not found — the requested resource does not exist", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict — the request collides with current resource state", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error — see the message field for details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "502": { + "description": "Bad gateway — an upstream provider returned an error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "503": { + "description": "Service unavailable — try again shortly", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Service Subscriptions" + ], + "summary": "Remove a subscription by its ID", + "description": "Removes a specific subscription (whole-service or component-level). No-op if not found.", + "operationId": "unsubscribe_1", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "400": { + "description": "Bad request — the payload failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized — missing or invalid credentials", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden — the actor lacks permission for this resource", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Not found — the requested resource does not exist", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict — the request collides with current resource state", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error — see the message field for details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "502": { + "description": "Bad gateway — an upstream provider returned an error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "503": { + "description": "Service unavailable — try again shortly", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/api/v1/service-subscriptions/{id}/alert-sensitivity": { + "patch": { + "tags": [ + "Service Subscriptions" + ], + "summary": "Update alert sensitivity for a subscription", + "description": "Controls which external incidents trigger alerts and whether they page anyone: ALL (any status change, paged), INCIDENTS_ONLY (real vendor incidents, paged), MAJOR_ONLY (only DOWN-level incidents, paged), AWARENESS (real vendor incidents tracked silently — visible on the dashboard but no alert channels fire; default for new subscriptions).", + "operationId": "updateAlertSensitivity", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateAlertSensitivityRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/SingleValueResponseServiceSubscriptionDto" + } + } + } + }, + "400": { + "description": "Bad request — the payload failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized — missing or invalid credentials", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden — the actor lacks permission for this resource", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Not found — the requested resource does not exist", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict — the request collides with current resource state", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error — see the message field for details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "502": { + "description": "Bad gateway — an upstream provider returned an error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "503": { + "description": "Service unavailable — try again shortly", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/api/v1/service-subscriptions/{slug}": { + "post": { + "tags": [ + "Service Subscriptions" + ], + "summary": "Subscribe to a service or a component of a service", + "description": "Idempotent — returns the existing subscription if an identical one exists. Omit the request body or set componentId to null for a whole-service subscription. When alertSensitivity is omitted, new subscriptions default to AWARENESS (silent tracking — the incident appears on the dashboard but no alert channels fire). PATCH /alert-sensitivity to opt in to paging. Free tier: max 10 subscriptions. Paid tier: unlimited.", + "operationId": "subscribe_1", + "parameters": [ + { + "name": "slug", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceSubscribeRequest" + } + } + } + }, + "responses": { + "201": { + "description": "Created", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/SingleValueResponseServiceSubscriptionDto" + } + } + } + }, + "400": { + "description": "Bad request — the payload failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized — missing or invalid credentials", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden — the actor lacks permission for this resource", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Not found — the requested resource does not exist", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict — the request collides with current resource state", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error — see the message field for details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "502": { + "description": "Bad gateway — an upstream provider returned an error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "503": { + "description": "Service unavailable — try again shortly", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/api/v1/services": { + "get": { + "tags": [ + "Status Data" + ], + "summary": "List all enabled services (cursor-paginated)", + "operationId": "listServices", + "parameters": [ + { + "name": "category", + "in": "query", + "description": "Filter by category (exact match)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "status", + "in": "query", + "description": "Filter by current overall_status (exact match)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "published", + "in": "query", + "description": "Filter by published status for pSEO pages", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "name": "slaPublished", + "in": "query", + "description": "Filter by SLA page publication status", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "name": "search", + "in": "query", + "description": "Case-insensitive substring match on service name or slug", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "sort", + "in": "query", + "description": "Result ordering: 'recent' (default, newest first) or 'curated' (curated/recognizable first)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "cursor", + "in": "query", + "description": "Opaque cursor from a previous response", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "description": "Page size (1–100, default 20)", + "required": false, + "schema": { + "type": "integer", + "format": "int32", + "default": 20 + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CursorPageServiceCatalogDto" + } + } + } + }, + "400": { + "description": "Bad request — the payload failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized — missing or invalid credentials", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden — the actor lacks permission for this resource", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Not found — the requested resource does not exist", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict — the request collides with current resource state", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error — see the message field for details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "502": { + "description": "Bad gateway — an upstream provider returned an error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "503": { + "description": "Service unavailable — try again shortly", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/api/v1/services/{slugOrId}": { + "get": { + "tags": [ + "Status Data" + ], + "summary": "Get a single service by slug or UUID with current status, components, and recent incidents", + "description": "When ``summary=true``, the inline ``components`` list is trimmed to groups + showcase leaves + currently-impacted leaves + ungrouped leaves, and a ``componentsSummary`` block is added with the trimmed counts. Powers SSR for vendors with hundreds of components (Snowflake, Cloudflare, DigitalOcean) without OOM-ing the renderer. Default false for full back-compat.", + "operationId": "getService", + "parameters": [ + { + "name": "slugOrId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "summary", + "in": "query", + "description": "Return a curated subset of components (groups + showcase + impacted + ungrouped) and a componentsSummary block; default false", + "required": false, + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "publishedOnly", + "in": "query", + "description": "Resolve only published services (curated public pSEO set); 404 otherwise. Default false", + "required": false, + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/SingleValueResponseServiceDetailDto" + } + } + } + }, + "400": { + "description": "Bad request — the payload failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized — missing or invalid credentials", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden — the actor lacks permission for this resource", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Not found — the requested resource does not exist", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict — the request collides with current resource state", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error — see the message field for details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "502": { + "description": "Bad gateway — an upstream provider returned an error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "503": { + "description": "Service unavailable — try again shortly", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/api/v1/services/{slugOrId}/components": { + "get": { + "tags": [ + "Status Data" + ], + "summary": "List active components for a service with current status and inline uptime", + "description": "When ``groupId`` is supplied, only direct children of that group are returned — used by the pSEO renderer to lazy-load the leaves under a group that summary mode trimmed. Without ``groupId`` the response includes every active component for the service. Supports pagination via ``page``/``size`` and case-insensitive name search via ``search``.", + "operationId": "getComponents", + "parameters": [ + { + "name": "slugOrId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "groupId", + "in": "query", + "description": "Restrict result to direct children of this group component id", + "required": false, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "search", + "in": "query", + "description": "Case-insensitive substring match on component name", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "page", + "in": "query", + "description": "Zero-based page index", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "size", + "in": "query", + "description": "Page size (default 25, max 100)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/TableValueResultServiceComponentDto" + } + } + } + }, + "400": { + "description": "Bad request — the payload failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized — missing or invalid credentials", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden — the actor lacks permission for this resource", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Not found — the requested resource does not exist", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict — the request collides with current resource state", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error — see the message field for details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "502": { + "description": "Bad gateway — an upstream provider returned an error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "503": { + "description": "Service unavailable — try again shortly", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/api/v1/services/{slugOrId}/components/{componentId}/uptime": { + "get": { + "tags": [ + "Status Data" + ], + "summary": "Get daily uptime data for a component", + "description": "Pass either ``period`` (preset window) or an explicit ``from``/``to`` calendar window (ISO yyyy-MM-dd, max 730 days, ``to`` defaults to today). When both are supplied, the explicit window wins.", + "operationId": "getComponentUptime", + "parameters": [ + { + "name": "slugOrId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "componentId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "period", + "in": "query", + "description": "Preset time window (used when ``from`` is omitted)", + "required": false, + "schema": { + "type": "string", + "enum": [ + "7d", + "30d", + "90d", + "1y" + ] + } + }, + { + "name": "from", + "in": "query", + "description": "Explicit window start (ISO date); overrides ``period``", + "required": false, + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "to", + "in": "query", + "description": "Explicit window end (ISO date); defaults to today", + "required": false, + "schema": { + "type": "string", + "format": "date" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/TableValueResultComponentUptimeDayDto" + } + } + } + }, + "400": { + "description": "Bad request — the payload failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized — missing or invalid credentials", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden — the actor lacks permission for this resource", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Not found — the requested resource does not exist", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict — the request collides with current resource state", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error — see the message field for details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "502": { + "description": "Bad gateway — an upstream provider returned an error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "503": { + "description": "Service unavailable — try again shortly", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/api/v1/services/{slugOrId}/components/uptime": { + "get": { + "tags": [ + "Status Data" ], - "summary": "Subscribe to a service or a component of a service", - "description": "Idempotent — returns the existing subscription if an identical one exists. Omit the request body or set componentId to null for a whole-service subscription. When alertSensitivity is omitted, new subscriptions default to AWARENESS (silent tracking — the incident appears on the dashboard but no alert channels fire). PATCH /alert-sensitivity to opt in to paging. Free tier: max 10 subscriptions. Paid tier: unlimited.", - "operationId": "subscribe_1", + "summary": "Batch daily uptime data for all leaf components", + "description": "Returns daily uptime for every active non-group component with uptime data, keyed by component ID. Replaces N individual per-component uptime calls with a single request. Supports either a preset ``period`` or an explicit ``from``/``to`` window (ISO yyyy-MM-dd, max 730 days). The explicit window wins when both are supplied — this is what powers the sliding 90-day navigator on the public uptime history page.", + "operationId": "getBatchComponentUptime", "parameters": [ { - "name": "slug", + "name": "slugOrId", "in": "path", "required": true, "schema": { "type": "string" } + }, + { + "name": "period", + "in": "query", + "description": "Preset time window (used when ``from`` is omitted)", + "required": false, + "schema": { + "type": "string", + "enum": [ + "7d", + "30d", + "90d", + "1y" + ] + } + }, + { + "name": "from", + "in": "query", + "description": "Explicit window start (ISO date); overrides ``period``", + "required": false, + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "to", + "in": "query", + "description": "Explicit window end (ISO date); defaults to today", + "required": false, + "schema": { + "type": "string", + "format": "date" + } } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ServiceSubscribeRequest" + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/SingleValueResponseBatchComponentUptimeDto" + } + } + } + }, + "400": { + "description": "Bad request — the payload failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized — missing or invalid credentials", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden — the actor lacks permission for this resource", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Not found — the requested resource does not exist", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict — the request collides with current resource state", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error — see the message field for details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "502": { + "description": "Bad gateway — an upstream provider returned an error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "503": { + "description": "Service unavailable — try again shortly", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } } } } - }, + } + } + }, + "/api/v1/services/{slugOrId}/days/{date}": { + "get": { + "tags": [ + "Status Data" + ], + "summary": "One-day rollup for a service: aggregated uptime, per-component impacts, and overlapping incidents", + "description": "Powers the click/hover-to-expand panel under each uptime bar on the public status page. Single round-trip — components, sums, and overlapping incidents (with affected component names) are returned in one response.", + "operationId": "getServiceDayDetail", + "parameters": [ + { + "name": "slugOrId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "date", + "in": "path", + "description": "UTC calendar day in ISO format (YYYY-MM-DD)", + "required": true, + "schema": { + "type": "string", + "format": "date" + } + } + ], "responses": { - "201": { - "description": "Created", + "200": { + "description": "OK", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseServiceSubscriptionDto" + "$ref": "#/components/schemas/SingleValueResponseServiceDayDetailDto" } } } @@ -13497,77 +15456,283 @@ } } }, - "/api/v1/services": { + "/api/v1/services/{slugOrId}/incidents": { "get": { "tags": [ "Status Data" ], - "summary": "List all enabled services (cursor-paginated)", - "operationId": "listServices", + "summary": "List incident history for a service (paginated)", + "operationId": "listIncidents_1", "parameters": [ { - "name": "category", - "in": "query", - "description": "Filter by category (exact match)", - "required": false, + "name": "slugOrId", + "in": "path", + "required": true, "schema": { "type": "string" } }, { - "name": "status", + "name": "from", "in": "query", - "description": "Filter by current overall_status (exact match)", + "description": "Earliest start date (ISO 8601 date)", "required": false, "schema": { - "type": "string" + "type": "string", + "format": "date" } }, { - "name": "published", + "name": "status", "in": "query", - "description": "Filter by published status for pSEO pages", + "description": "Filter: active (unresolved), resolved, or omit for all", "required": false, "schema": { - "type": "boolean" + "type": "string", + "enum": [ + "active", + "resolved" + ] } }, { - "name": "search", + "name": "pageable", "in": "query", - "description": "Case-insensitive substring match on service name or slug", - "required": false, + "required": true, "schema": { - "type": "string" + "$ref": "#/components/schemas/Pageable" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/TableValueResultServiceIncidentDto" + } + } + } + }, + "400": { + "description": "Bad request — the payload failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized — missing or invalid credentials", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden — the actor lacks permission for this resource", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Not found — the requested resource does not exist", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict — the request collides with current resource state", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error — see the message field for details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "502": { + "description": "Bad gateway — an upstream provider returned an error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } } }, + "503": { + "description": "Service unavailable — try again shortly", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/api/v1/services/{slugOrId}/incidents/{incidentId}": { + "get": { + "tags": [ + "Status Data" + ], + "summary": "Get incident detail with full update timeline", + "operationId": "getIncident_1", + "parameters": [ { - "name": "sort", - "in": "query", - "description": "Result ordering: 'recent' (default, newest first) or 'curated' (curated/recognizable first)", - "required": false, + "name": "slugOrId", + "in": "path", + "required": true, "schema": { "type": "string" } }, { - "name": "cursor", - "in": "query", - "description": "Opaque cursor from a previous response", - "required": false, + "name": "incidentId", + "in": "path", + "required": true, "schema": { - "type": "string" + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/SingleValueResponseServiceIncidentDetailDto" + } + } + } + }, + "400": { + "description": "Bad request — the payload failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized — missing or invalid credentials", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden — the actor lacks permission for this resource", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Not found — the requested resource does not exist", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict — the request collides with current resource state", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error — see the message field for details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "502": { + "description": "Bad gateway — an upstream provider returned an error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } } }, + "503": { + "description": "Service unavailable — try again shortly", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/api/v1/services/{slugOrId}/live-status": { + "get": { + "tags": [ + "Status Data" + ], + "summary": "Lightweight live-status snapshot for polling", + "description": "Returns only the current overall status, component statuses, and active incident count. Designed for frequent polling with minimal payload.", + "operationId": "getServiceLiveStatus", + "parameters": [ { - "name": "limit", - "in": "query", - "description": "Page size (1–100, default 20)", - "required": false, + "name": "slugOrId", + "in": "path", + "required": true, "schema": { - "type": "integer", - "format": "int32", - "default": 20 + "type": "string" } } ], @@ -13577,7 +15742,7 @@ "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/CursorPageServiceCatalogDto" + "$ref": "#/components/schemas/SingleValueResponseServiceLiveStatusDto" } } } @@ -13665,14 +15830,13 @@ } } }, - "/api/v1/services/{slugOrId}": { + "/api/v1/services/{slugOrId}/maintenances": { "get": { "tags": [ "Status Data" ], - "summary": "Get a single service by slug or UUID with current status, components, and recent incidents", - "description": "When ``summary=true``, the inline ``components`` list is trimmed to groups + showcase leaves + currently-impacted leaves + ungrouped leaves, and a ``componentsSummary`` block is added with the trimmed counts. Powers SSR for vendors with hundreds of components (Snowflake, Cloudflare, DigitalOcean) without OOM-ing the renderer. Default false for full back-compat.", - "operationId": "getService", + "summary": "List scheduled maintenances for a service", + "operationId": "getScheduledMaintenances", "parameters": [ { "name": "slugOrId", @@ -13683,23 +15847,15 @@ } }, { - "name": "summary", - "in": "query", - "description": "Return a curated subset of components (groups + showcase + impacted + ungrouped) and a componentsSummary block; default false", - "required": false, - "schema": { - "type": "boolean", - "default": false - } - }, - { - "name": "publishedOnly", + "name": "status", "in": "query", - "description": "Resolve only published services (curated public pSEO set); 404 otherwise. Default false", + "description": "Filter by status (e.g. scheduled, in_progress, verifying, completed)", "required": false, "schema": { - "type": "boolean", - "default": false + "type": "array", + "items": { + "type": "string" + } } } ], @@ -13709,7 +15865,7 @@ "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseServiceDetailDto" + "$ref": "#/components/schemas/TableValueResultScheduledMaintenanceDto" } } } @@ -13797,14 +15953,13 @@ } } }, - "/api/v1/services/{slugOrId}/components": { + "/api/v1/services/{slugOrId}/poll-results": { "get": { "tags": [ "Status Data" ], - "summary": "List active components for a service with current status and inline uptime", - "description": "When ``groupId`` is supplied, only direct children of that group are returned — used by the pSEO renderer to lazy-load the leaves under a group that summary mode trimmed. Without ``groupId`` the response includes every active component for the service.", - "operationId": "getComponents", + "summary": "List poll results for a service (cursor-paginated)", + "operationId": "listPollResults", "parameters": [ { "name": "slugOrId", @@ -13815,13 +15970,23 @@ } }, { - "name": "groupId", + "name": "cursor", "in": "query", - "description": "Restrict result to direct children of this group component id", + "description": "ISO 8601 timestamp cursor from a previous response", "required": false, "schema": { - "type": "string", - "format": "uuid" + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "description": "Page size (1–100, default 50)", + "required": false, + "schema": { + "type": "integer", + "format": "int32", + "default": 50 } } ], @@ -13831,7 +15996,7 @@ "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/TableValueResultServiceComponentDto" + "$ref": "#/components/schemas/CursorPageServicePollResultDto" } } } @@ -13919,14 +16084,13 @@ } } }, - "/api/v1/services/{slugOrId}/components/{componentId}/uptime": { + "/api/v1/services/{slugOrId}/poll-summary": { "get": { "tags": [ "Status Data" ], - "summary": "Get daily uptime data for a component", - "description": "Pass either ``period`` (preset window) or an explicit ``from``/``to`` calendar window (ISO yyyy-MM-dd, max 730 days, ``to`` defaults to today). When both are supplied, the explicit window wins.", - "operationId": "getComponentUptime", + "summary": "Get aggregated poll metrics and chart data for a service", + "operationId": "getPollSummary", "parameters": [ { "name": "slugOrId", @@ -13937,48 +16101,18 @@ } }, { - "name": "componentId", - "in": "path", - "required": true, - "schema": { - "type": "string", - "format": "uuid" - } - }, - { - "name": "period", + "name": "window", "in": "query", - "description": "Preset time window (used when ``from`` is omitted)", + "description": "Time window", "required": false, "schema": { "type": "string", "enum": [ + "24h", "7d", - "30d", - "90d", - "1y" + "30d" ] } - }, - { - "name": "from", - "in": "query", - "description": "Explicit window start (ISO date); overrides ``period``", - "required": false, - "schema": { - "type": "string", - "format": "date" - } - }, - { - "name": "to", - "in": "query", - "description": "Explicit window end (ISO date); defaults to today", - "required": false, - "schema": { - "type": "string", - "format": "date" - } } ], "responses": { @@ -13987,7 +16121,7 @@ "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/TableValueResultComponentUptimeDayDto" + "$ref": "#/components/schemas/SingleValueResponseServicePollSummaryDto" } } } @@ -14075,14 +16209,14 @@ } } }, - "/api/v1/services/{slugOrId}/components/uptime": { + "/api/v1/services/{slugOrId}/status-events": { "get": { "tags": [ "Status Data" ], - "summary": "Batch daily uptime data for all leaf components", - "description": "Returns daily uptime for every active non-group component with uptime data, keyed by component ID. Replaces N individual per-component uptime calls with a single request. Supports either a preset ``period`` or an explicit ``from``/``to`` window (ISO yyyy-MM-dd, max 730 days). The explicit window wins when both are supplied — this is what powers the sliding 90-day navigator on the public uptime history page.", - "operationId": "getBatchComponentUptime", + "summary": "List curated vendor status events for a service", + "description": "Reverse-chronological merge of vendor incidents, maintenances, and rolled-up component transitions for the Dependencies Detail rail. Optional JWT + x-phelm-org-id annotates incident.opened rows with the caller's linked internal incident.", + "operationId": "listStatusEvents", "parameters": [ { "name": "slugOrId", @@ -14092,39 +16226,67 @@ "type": "string" } }, + { + "name": "types", + "in": "query", + "description": "Comma-separated type buckets: incident, maintenance, component (default: all)", + "required": false, + "schema": { + "type": "string" + } + }, { "name": "period", "in": "query", - "description": "Preset time window (used when ``from`` is omitted)", + "description": "Preset window", "required": false, "schema": { "type": "string", "enum": [ "7d", "30d", - "90d", - "1y" + "90d" ] } }, { "name": "from", "in": "query", - "description": "Explicit window start (ISO date); overrides ``period``", + "description": "Explicit lower bound (ISO 8601); overrides period", "required": false, "schema": { "type": "string", - "format": "date" + "format": "date-time" } }, { "name": "to", "in": "query", - "description": "Explicit window end (ISO date); defaults to today", + "description": "Explicit upper bound (ISO 8601); default now", "required": false, "schema": { "type": "string", - "format": "date" + "format": "date-time" + } + }, + { + "name": "cursor", + "in": "query", + "description": "Opaque cursor from a previous response", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "description": "Page size (1–100, default 50)", + "required": false, + "schema": { + "type": "integer", + "format": "int32", + "default": 50 } } ], @@ -14134,7 +16296,7 @@ "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseBatchComponentUptimeDto" + "$ref": "#/components/schemas/CursorPageStatusEventDto" } } } @@ -14222,14 +16384,14 @@ } } }, - "/api/v1/services/{slugOrId}/days/{date}": { + "/api/v1/services/{slugOrId}/uptime": { "get": { "tags": [ "Status Data" ], - "summary": "One-day rollup for a service: aggregated uptime, per-component impacts, and overlapping incidents", - "description": "Powers the click/hover-to-expand panel under each uptime bar on the public status page. Single round-trip — components, sums, and overlapping incidents (with affected component names) are returned in one response.", - "operationId": "getServiceDayDetail", + "summary": "Get uptime statistics for a service", + "description": "Uptime data aggregated across active non-group components.", + "operationId": "getServiceUptime", "parameters": [ { "name": "slugOrId", @@ -14240,13 +16402,35 @@ } }, { - "name": "date", - "in": "path", - "description": "UTC calendar day in ISO format (YYYY-MM-DD)", - "required": true, + "name": "period", + "in": "query", + "description": "Time window", + "required": false, "schema": { "type": "string", - "format": "date" + "enum": [ + "24h", + "7d", + "30d", + "90d", + "1y", + "2y", + "all" + ] + } + }, + { + "name": "granularity", + "in": "query", + "description": "Bucket granularity", + "required": false, + "schema": { + "type": "string", + "enum": [ + "hourly", + "daily", + "monthly" + ] } } ], @@ -14256,7 +16440,7 @@ "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseServiceDayDetailDto" + "$ref": "#/components/schemas/SingleValueResponseServiceUptimeResponse" } } } @@ -14341,25 +16525,23 @@ } } } - } + }, + "security": [ + { + "BearerAuth": [] + } + ] } }, - "/api/v1/services/{slugOrId}/incidents": { + "/api/v1/services/incidents": { "get": { "tags": [ "Status Data" ], - "summary": "List incident history for a service (paginated)", - "operationId": "listIncidents_1", + "summary": "List vendor incidents across all services (paginated)", + "description": "Cross-service vendor incident feed ordered by start date descending.", + "operationId": "listCrossServiceIncidents", "parameters": [ - { - "name": "slugOrId", - "in": "path", - "required": true, - "schema": { - "type": "string" - } - }, { "name": "from", "in": "query", @@ -14383,6 +16565,15 @@ ] } }, + { + "name": "category", + "in": "query", + "description": "Filter by service category", + "required": false, + "schema": { + "type": "string" + } + }, { "name": "pageable", "in": "query", @@ -14486,29 +16677,23 @@ } } }, - "/api/v1/services/{slugOrId}/incidents/{incidentId}": { + "/api/v1/services/summary": { "get": { "tags": [ "Status Data" ], - "summary": "Get incident detail with full update timeline", - "operationId": "getIncident_1", + "summary": "Global status summary across all services", + "description": "Returns aggregate counts of services by status and a list of services currently experiencing issues.", + "operationId": "getGlobalStatusSummary", "parameters": [ { - "name": "slugOrId", - "in": "path", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "incidentId", - "in": "path", - "required": true, + "name": "publishedOnly", + "in": "query", + "description": "Aggregate only published services (curated public pSEO set); default false", + "required": false, "schema": { - "type": "string", - "format": "uuid" + "type": "boolean", + "default": false } } ], @@ -14518,7 +16703,7 @@ "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseServiceIncidentDetailDto" + "$ref": "#/components/schemas/SingleValueResponseGlobalStatusSummaryDto" } } } @@ -14606,31 +16791,20 @@ } } }, - "/api/v1/services/{slugOrId}/live-status": { + "/api/v1/status-pages": { "get": { "tags": [ - "Status Data" - ], - "summary": "Lightweight live-status snapshot for polling", - "description": "Returns only the current overall status, component statuses, and active incident count. Designed for frequent polling with minimal payload.", - "operationId": "getServiceLiveStatus", - "parameters": [ - { - "name": "slugOrId", - "in": "path", - "required": true, - "schema": { - "type": "string" - } - } + "Status Pages" ], + "summary": "List status pages for the workspace", + "operationId": "list_4", "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseServiceLiveStatusDto" + "$ref": "#/components/schemas/TableValueResultStatusPageDto" } } } @@ -14716,44 +16890,30 @@ } } } - } - }, - "/api/v1/services/{slugOrId}/maintenances": { - "get": { + }, + "post": { "tags": [ - "Status Data" + "Status Pages" ], - "summary": "List scheduled maintenances for a service", - "operationId": "getScheduledMaintenances", - "parameters": [ - { - "name": "slugOrId", - "in": "path", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "status", - "in": "query", - "description": "Filter by status (e.g. scheduled, in_progress, verifying, completed)", - "required": false, - "schema": { - "type": "array", - "items": { - "type": "string" + "summary": "Create a status page", + "operationId": "create_5", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateStatusPageRequest" } } - } - ], + }, + "required": true + }, "responses": { - "200": { - "description": "OK", + "201": { + "description": "Created", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/TableValueResultScheduledMaintenanceDto" + "$ref": "#/components/schemas/SingleValueResponseStatusPageDto" } } } @@ -14841,40 +17001,21 @@ } } }, - "/api/v1/services/{slugOrId}/poll-results": { + "/api/v1/status-pages/{id}": { "get": { "tags": [ - "Status Data" + "Status Pages" ], - "summary": "List poll results for a service (cursor-paginated)", - "operationId": "listPollResults", + "summary": "Get a status page", + "operationId": "get_2", "parameters": [ { - "name": "slugOrId", + "name": "id", "in": "path", "required": true, "schema": { - "type": "string" - } - }, - { - "name": "cursor", - "in": "query", - "description": "ISO 8601 timestamp cursor from a previous response", - "required": false, - "schema": { - "type": "string" - } - }, - { - "name": "limit", - "in": "query", - "description": "Page size (1–100, default 50)", - "required": false, - "schema": { - "type": "integer", - "format": "int32", - "default": 50 + "type": "string", + "format": "uuid" } } ], @@ -14884,7 +17025,7 @@ "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/CursorPageServicePollResultDto" + "$ref": "#/components/schemas/SingleValueResponseStatusPageDto" } } } @@ -14970,46 +17111,41 @@ } } } - } - }, - "/api/v1/services/{slugOrId}/poll-summary": { - "get": { + }, + "put": { "tags": [ - "Status Data" + "Status Pages" ], - "summary": "Get aggregated poll metrics and chart data for a service", - "operationId": "getPollSummary", + "summary": "Update a status page", + "operationId": "update_3", "parameters": [ { - "name": "slugOrId", + "name": "id", "in": "path", "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "window", - "in": "query", - "description": "Time window", - "required": false, "schema": { "type": "string", - "enum": [ - "24h", - "7d", - "30d" - ] + "format": "uuid" } } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateStatusPageRequest" + } + } + }, + "required": true + }, "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseServicePollSummaryDto" + "$ref": "#/components/schemas/SingleValueResponseStatusPageDto" } } } @@ -15095,68 +17231,27 @@ } } } - } - }, - "/api/v1/services/{slugOrId}/uptime": { - "get": { + }, + "delete": { "tags": [ - "Status Data" + "Status Pages" ], - "summary": "Get uptime statistics for a service", - "description": "Uptime data aggregated across active non-group components.", - "operationId": "getServiceUptime", + "summary": "Delete a status page", + "operationId": "delete_3", "parameters": [ { - "name": "slugOrId", + "name": "id", "in": "path", "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "period", - "in": "query", - "description": "Time window", - "required": false, "schema": { "type": "string", - "enum": [ - "24h", - "7d", - "30d", - "90d", - "1y", - "2y", - "all" - ] - } - }, - { - "name": "granularity", - "in": "query", - "description": "Bucket granularity", - "required": false, - "schema": { - "type": "string", - "enum": [ - "hourly", - "daily", - "monthly" - ] + "format": "uuid" } } ], "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/SingleValueResponseServiceUptimeResponse" - } - } - } + "204": { + "description": "No Content" }, "400": { "description": "Bad request — the payload failed validation", @@ -15238,61 +17333,24 @@ } } } - }, - "security": [ - { - "BearerAuth": [] - } - ] + } } }, - "/api/v1/services/incidents": { + "/api/v1/status-pages/{id}/components": { "get": { "tags": [ - "Status Data" + "Status Pages" ], - "summary": "List vendor incidents across all services (paginated)", - "description": "Cross-service vendor incident feed ordered by start date descending.", - "operationId": "listCrossServiceIncidents", + "summary": "List all components", + "operationId": "listComponents", "parameters": [ { - "name": "from", - "in": "query", - "description": "Earliest start date (ISO 8601 date)", - "required": false, - "schema": { - "type": "string", - "format": "date" - } - }, - { - "name": "status", - "in": "query", - "description": "Filter: active (unresolved), resolved, or omit for all", - "required": false, - "schema": { - "type": "string", - "enum": [ - "active", - "resolved" - ] - } - }, - { - "name": "category", - "in": "query", - "description": "Filter by service category", - "required": false, - "schema": { - "type": "string" - } - }, - { - "name": "pageable", - "in": "query", + "name": "id", + "in": "path", "required": true, "schema": { - "$ref": "#/components/schemas/Pageable" + "type": "string", + "format": "uuid" } } ], @@ -15302,7 +17360,7 @@ "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/TableValueResultServiceIncidentDto" + "$ref": "#/components/schemas/TableValueResultStatusPageComponentDto" } } } @@ -15388,35 +17446,41 @@ } } } - } - }, - "/api/v1/services/summary": { - "get": { + }, + "post": { "tags": [ - "Status Data" + "Status Pages" ], - "summary": "Global status summary across all services", - "description": "Returns aggregate counts of services by status and a list of services currently experiencing issues.", - "operationId": "getGlobalStatusSummary", + "summary": "Add a component to the status page", + "operationId": "createComponent", "parameters": [ { - "name": "publishedOnly", - "in": "query", - "description": "Aggregate only published services (curated public pSEO set); default false", - "required": false, + "name": "id", + "in": "path", + "required": true, "schema": { - "type": "boolean", - "default": false + "type": "string", + "format": "uuid" } } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateStatusPageComponentRequest" + } + } + }, + "required": true + }, "responses": { - "200": { - "description": "OK", + "201": { + "description": "Created", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseGlobalStatusSummaryDto" + "$ref": "#/components/schemas/SingleValueResponseStatusPageComponentDto" } } } @@ -15504,20 +17568,50 @@ } } }, - "/api/v1/status-pages": { - "get": { + "/api/v1/status-pages/{id}/components/{componentId}": { + "put": { "tags": [ "Status Pages" ], - "summary": "List status pages for the workspace", - "operationId": "list_4", + "summary": "Update a component", + "operationId": "updateComponent", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "componentId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateStatusPageComponentRequest" + } + } + }, + "required": true + }, "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/TableValueResultStatusPageDto" + "$ref": "#/components/schemas/SingleValueResponseStatusPageComponentDto" } } } @@ -15604,32 +17698,35 @@ } } }, - "post": { + "delete": { "tags": [ "Status Pages" ], - "summary": "Create a status page", - "operationId": "create_5", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateStatusPageRequest" - } + "summary": "Remove a component from the status page", + "operationId": "deleteComponent", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" } }, - "required": true - }, - "responses": { - "201": { - "description": "Created", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/SingleValueResponseStatusPageDto" - } - } + { + "name": "componentId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" } + } + ], + "responses": { + "204": { + "description": "No Content" }, "400": { "description": "Bad request — the payload failed validation", @@ -15714,13 +17811,14 @@ } } }, - "/api/v1/status-pages/{id}": { + "/api/v1/status-pages/{id}/components/{componentId}/measured-uptime": { "get": { "tags": [ "Status Pages" ], - "summary": "Get a status page", - "operationId": "get_2", + "summary": "Get measured (check-based) component uptime history", + "description": "Additive measured daily uptime for MONITOR components (ASK-SP-2 / CHG-2). Reads time-bounded check_results_daily rollups for the linked monitor. Response source is always measured. Does not change legacy GET …/uptime incident-window semantics. days default 90, max 365.", + "operationId": "componentMeasuredUptime", "parameters": [ { "name": "id", @@ -15730,6 +17828,25 @@ "type": "string", "format": "uuid" } + }, + { + "name": "componentId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "days", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "format": "int32", + "default": 90 + } } ], "responses": { @@ -15738,7 +17855,7 @@ "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseStatusPageDto" + "$ref": "#/components/schemas/SingleValueResponseStatusPageMeasuredComponentUptimeDto" } } } @@ -15824,13 +17941,16 @@ } } } - }, + } + }, + "/api/v1/status-pages/{id}/components/{componentId}/override": { "put": { "tags": [ "Status Pages" ], - "summary": "Update a status page", - "operationId": "update_3", + "summary": "Set a timed human status override on a component", + "description": "ASK-SP-1 / CHG-1. Effective currentStatus reflects the override until expiry or clear, unless an active incident takes precedence (incident > override > binding). Max expiry horizon is 24 hours.", + "operationId": "setComponentOverride", "parameters": [ { "name": "id", @@ -15840,13 +17960,22 @@ "type": "string", "format": "uuid" } + }, + { + "name": "componentId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } } ], "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/UpdateStatusPageRequest" + "$ref": "#/components/schemas/SetStatusPageComponentOverrideRequest" } } }, @@ -15858,7 +17987,7 @@ "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseStatusPageDto" + "$ref": "#/components/schemas/SingleValueResponseStatusPageComponentDto" } } } @@ -15949,8 +18078,8 @@ "tags": [ "Status Pages" ], - "summary": "Delete a status page", - "operationId": "delete_3", + "summary": "Clear a timed human status override on a component", + "operationId": "clearComponentOverride", "parameters": [ { "name": "id", @@ -15960,11 +18089,27 @@ "type": "string", "format": "uuid" } + }, + { + "name": "componentId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } } ], "responses": { - "204": { - "description": "No Content" + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/SingleValueResponseStatusPageComponentDto" + } + } + } }, "400": { "description": "Bad request — the payload failed validation", @@ -16049,13 +18194,14 @@ } } }, - "/api/v1/status-pages/{id}/components": { + "/api/v1/status-pages/{id}/components/{componentId}/uptime": { "get": { "tags": [ "Status Pages" ], - "summary": "List all components", - "operationId": "listComponents", + "summary": "Get component uptime history from published incident windows", + "description": "Legacy incident-window rollup (source semantics: incident_window). Daily % is derived from published status-page incident windows, not probe checks. For measured check-based uptime use GET …/measured-uptime (ASK-SP-2 / CHG-2).", + "operationId": "componentUptime_1", "parameters": [ { "name": "id", @@ -16065,6 +18211,25 @@ "type": "string", "format": "uuid" } + }, + { + "name": "componentId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "days", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "format": "int32", + "default": 90 + } } ], "responses": { @@ -16073,7 +18238,7 @@ "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/TableValueResultStatusPageComponentDto" + "$ref": "#/components/schemas/TableValueResultComponentUptimeDayDto" } } } @@ -16159,13 +18324,15 @@ } } } - }, - "post": { + } + }, + "/api/v1/status-pages/{id}/components/reorder": { + "put": { "tags": [ "Status Pages" ], - "summary": "Add a component to the status page", - "operationId": "createComponent", + "summary": "Batch reorder components (and optionally move between groups)", + "operationId": "reorderComponents", "parameters": [ { "name": "id", @@ -16181,22 +18348,15 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/CreateStatusPageComponentRequest" + "$ref": "#/components/schemas/ReorderComponentsRequest" } } }, "required": true }, "responses": { - "201": { - "description": "Created", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/SingleValueResponseStatusPageComponentDto" - } - } - } + "204": { + "description": "No Content" }, "400": { "description": "Bad request — the payload failed validation", @@ -16281,13 +18441,13 @@ } } }, - "/api/v1/status-pages/{id}/components/{componentId}": { - "put": { + "/api/v1/status-pages/{id}/domains": { + "get": { "tags": [ "Status Pages" ], - "summary": "Update a component", - "operationId": "updateComponent", + "summary": "List custom domains", + "operationId": "listDomains", "parameters": [ { "name": "id", @@ -16297,34 +18457,15 @@ "type": "string", "format": "uuid" } - }, - { - "name": "componentId", - "in": "path", - "required": true, - "schema": { - "type": "string", - "format": "uuid" - } } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateStatusPageComponentRequest" - } - } - }, - "required": true - }, "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseStatusPageComponentDto" + "$ref": "#/components/schemas/TableValueResultStatusPageCustomDomainDto" } } } @@ -16411,12 +18552,12 @@ } } }, - "delete": { + "post": { "tags": [ "Status Pages" ], - "summary": "Remove a component from the status page", - "operationId": "deleteComponent", + "summary": "Add a custom domain", + "operationId": "addDomain", "parameters": [ { "name": "id", @@ -16426,20 +18567,28 @@ "type": "string", "format": "uuid" } - }, - { - "name": "componentId", - "in": "path", - "required": true, - "schema": { - "type": "string", - "format": "uuid" - } } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddCustomDomainRequest" + } + } + }, + "required": true + }, "responses": { - "204": { - "description": "No Content" + "201": { + "description": "Created", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/SingleValueResponseStatusPageCustomDomainDto" + } + } + } }, "400": { "description": "Bad request — the payload failed validation", @@ -16524,13 +18673,13 @@ } } }, - "/api/v1/status-pages/{id}/components/{componentId}/uptime": { - "get": { + "/api/v1/status-pages/{id}/domains/{domainId}": { + "delete": { "tags": [ "Status Pages" ], - "summary": "Get component uptime history (daily rollups)", - "operationId": "componentUptime_1", + "summary": "Remove a custom domain", + "operationId": "removeDomain", "parameters": [ { "name": "id", @@ -16542,35 +18691,18 @@ } }, { - "name": "componentId", + "name": "domainId", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } - }, - { - "name": "days", - "in": "query", - "required": false, - "schema": { - "type": "integer", - "format": "int32", - "default": 90 - } } ], "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/TableValueResultComponentUptimeDayDto" - } - } - } + "204": { + "description": "No Content" }, "400": { "description": "Bad request — the payload failed validation", @@ -16655,13 +18787,13 @@ } } }, - "/api/v1/status-pages/{id}/components/reorder": { - "put": { + "/api/v1/status-pages/{id}/domains/{domainId}/primary": { + "post": { "tags": [ "Status Pages" ], - "summary": "Batch reorder components (and optionally move between groups)", - "operationId": "reorderComponents", + "summary": "Mark a verified custom domain as the page's primary host", + "operationId": "setPrimaryDomain", "parameters": [ { "name": "id", @@ -16671,22 +18803,28 @@ "type": "string", "format": "uuid" } + }, + { + "name": "domainId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ReorderComponentsRequest" + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/SingleValueResponseStatusPageCustomDomainDto" + } } } }, - "required": true - }, - "responses": { - "204": { - "description": "No Content" - }, "400": { "description": "Bad request — the payload failed validation", "content": { @@ -16770,13 +18908,13 @@ } } }, - "/api/v1/status-pages/{id}/domains": { - "get": { + "/api/v1/status-pages/{id}/domains/{domainId}/verify": { + "post": { "tags": [ "Status Pages" ], - "summary": "List custom domains", - "operationId": "listDomains", + "summary": "Trigger domain verification check", + "operationId": "verifyDomain", "parameters": [ { "name": "id", @@ -16786,6 +18924,15 @@ "type": "string", "format": "uuid" } + }, + { + "name": "domainId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } } ], "responses": { @@ -16794,7 +18941,7 @@ "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/TableValueResultStatusPageCustomDomainDto" + "$ref": "#/components/schemas/SingleValueResponseStatusPageCustomDomainDto" } } } @@ -16880,13 +19027,15 @@ } } } - }, - "post": { + } + }, + "/api/v1/status-pages/{id}/groups": { + "get": { "tags": [ "Status Pages" ], - "summary": "Add a custom domain", - "operationId": "addDomain", + "summary": "List component groups with nested components", + "operationId": "listGroups", "parameters": [ { "name": "id", @@ -16898,23 +19047,13 @@ } } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AddCustomDomainRequest" - } - } - }, - "required": true - }, "responses": { - "201": { - "description": "Created", + "200": { + "description": "OK", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseStatusPageCustomDomainDto" + "$ref": "#/components/schemas/TableValueResultStatusPageComponentGroupDto" } } } @@ -17000,15 +19139,13 @@ } } } - } - }, - "/api/v1/status-pages/{id}/domains/{domainId}": { - "delete": { + }, + "post": { "tags": [ "Status Pages" ], - "summary": "Remove a custom domain", - "operationId": "removeDomain", + "summary": "Create a component group", + "operationId": "createGroup", "parameters": [ { "name": "id", @@ -17018,20 +19155,28 @@ "type": "string", "format": "uuid" } - }, - { - "name": "domainId", - "in": "path", - "required": true, - "schema": { - "type": "string", - "format": "uuid" - } } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateStatusPageComponentGroupRequest" + } + } + }, + "required": true + }, "responses": { - "204": { - "description": "No Content" + "201": { + "description": "Created", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/SingleValueResponseStatusPageComponentGroupDto" + } + } + } }, "400": { "description": "Bad request — the payload failed validation", @@ -17116,13 +19261,13 @@ } } }, - "/api/v1/status-pages/{id}/domains/{domainId}/primary": { - "post": { + "/api/v1/status-pages/{id}/groups/{groupId}": { + "put": { "tags": [ "Status Pages" ], - "summary": "Mark a verified custom domain as the page's primary host", - "operationId": "setPrimaryDomain", + "summary": "Update a component group", + "operationId": "updateGroup", "parameters": [ { "name": "id", @@ -17134,7 +19279,7 @@ } }, { - "name": "domainId", + "name": "groupId", "in": "path", "required": true, "schema": { @@ -17143,13 +19288,23 @@ } } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateStatusPageComponentGroupRequest" + } + } + }, + "required": true + }, "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseStatusPageCustomDomainDto" + "$ref": "#/components/schemas/SingleValueResponseStatusPageComponentGroupDto" } } } @@ -17235,15 +19390,13 @@ } } } - } - }, - "/api/v1/status-pages/{id}/domains/{domainId}/verify": { - "post": { + }, + "delete": { "tags": [ "Status Pages" ], - "summary": "Trigger domain verification check", - "operationId": "verifyDomain", + "summary": "Delete a component group (components become ungrouped)", + "operationId": "deleteGroup", "parameters": [ { "name": "id", @@ -17255,7 +19408,7 @@ } }, { - "name": "domainId", + "name": "groupId", "in": "path", "required": true, "schema": { @@ -17265,15 +19418,8 @@ } ], "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/SingleValueResponseStatusPageCustomDomainDto" - } - } - } + "204": { + "description": "No Content" }, "400": { "description": "Bad request — the payload failed validation", @@ -17358,13 +19504,13 @@ } } }, - "/api/v1/status-pages/{id}/groups": { + "/api/v1/status-pages/{id}/incidents": { "get": { "tags": [ "Status Pages" ], - "summary": "List component groups with nested components", - "operationId": "listGroups", + "summary": "List incidents for this status page (filterable by status, paginated)", + "operationId": "listIncidents", "parameters": [ { "name": "id", @@ -17374,6 +19520,31 @@ "type": "string", "format": "uuid" } + }, + { + "name": "status", + "in": "query", + "required": false, + "schema": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "INVESTIGATING", + "IDENTIFIED", + "MONITORING", + "RESOLVED" + ] + } + } + }, + { + "name": "pageable", + "in": "query", + "required": true, + "schema": { + "$ref": "#/components/schemas/Pageable" + } } ], "responses": { @@ -17382,7 +19553,7 @@ "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/TableValueResultStatusPageComponentGroupDto" + "$ref": "#/components/schemas/TableValueResultStatusPageIncidentDto" } } } @@ -17473,8 +19644,8 @@ "tags": [ "Status Pages" ], - "summary": "Create a component group", - "operationId": "createGroup", + "summary": "Create a status page incident (manual)", + "operationId": "createIncident", "parameters": [ { "name": "id", @@ -17490,7 +19661,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/CreateStatusPageComponentGroupRequest" + "$ref": "#/components/schemas/CreateStatusPageIncidentRequest" } } }, @@ -17502,7 +19673,7 @@ "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseStatusPageComponentGroupDto" + "$ref": "#/components/schemas/SingleValueResponseStatusPageIncidentDto" } } } @@ -17590,13 +19761,13 @@ } } }, - "/api/v1/status-pages/{id}/groups/{groupId}": { - "put": { + "/api/v1/status-pages/{id}/incidents/{incidentId}": { + "get": { "tags": [ "Status Pages" ], - "summary": "Update a component group", - "operationId": "updateGroup", + "summary": "Get incident details with timeline", + "operationId": "getIncident", "parameters": [ { "name": "id", @@ -17608,7 +19779,7 @@ } }, { - "name": "groupId", + "name": "incidentId", "in": "path", "required": true, "schema": { @@ -17617,23 +19788,13 @@ } } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateStatusPageComponentGroupRequest" - } - } - }, - "required": true - }, "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseStatusPageComponentGroupDto" + "$ref": "#/components/schemas/SingleValueResponseStatusPageIncidentDto" } } } @@ -17720,12 +19881,12 @@ } } }, - "delete": { + "put": { "tags": [ "Status Pages" ], - "summary": "Delete a component group (components become ungrouped)", - "operationId": "deleteGroup", + "summary": "Update an incident", + "operationId": "updateIncident", "parameters": [ { "name": "id", @@ -17737,7 +19898,7 @@ } }, { - "name": "groupId", + "name": "incidentId", "in": "path", "required": true, "schema": { @@ -17746,143 +19907,23 @@ } } ], - "responses": { - "204": { - "description": "No Content" - }, - "400": { - "description": "Bad request — the payload failed validation", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "401": { - "description": "Unauthorized — missing or invalid credentials", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "403": { - "description": "Forbidden — the actor lacks permission for this resource", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "404": { - "description": "Not found — the requested resource does not exist", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "409": { - "description": "Conflict — the request collides with current resource state", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "500": { - "description": "Internal server error — see the message field for details", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "502": { - "description": "Bad gateway — an upstream provider returned an error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "503": { - "description": "Service unavailable — try again shortly", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - } - } - } - }, - "/api/v1/status-pages/{id}/incidents": { - "get": { - "tags": [ - "Status Pages" - ], - "summary": "List incidents for this status page (filterable by status, paginated)", - "operationId": "listIncidents", - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "string", - "format": "uuid" - } - }, - { - "name": "status", - "in": "query", - "required": false, - "schema": { - "type": "array", - "items": { - "type": "string", - "enum": [ - "INVESTIGATING", - "IDENTIFIED", - "MONITORING", - "RESOLVED" - ] + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateStatusPageIncidentRequest" } } }, - { - "name": "pageable", - "in": "query", - "required": true, - "schema": { - "$ref": "#/components/schemas/Pageable" - } - } - ], + "required": true + }, "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/TableValueResultStatusPageIncidentDto" + "$ref": "#/components/schemas/SingleValueResponseStatusPageIncidentDto" } } } @@ -17969,12 +20010,12 @@ } } }, - "post": { + "delete": { "tags": [ "Status Pages" ], - "summary": "Create a status page incident (manual)", - "operationId": "createIncident", + "summary": "Delete an incident", + "operationId": "deleteIncident", "parameters": [ { "name": "id", @@ -17984,28 +20025,20 @@ "type": "string", "format": "uuid" } + }, + { + "name": "incidentId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateStatusPageIncidentRequest" - } - } - }, - "required": true - }, "responses": { - "201": { - "description": "Created", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/SingleValueResponseStatusPageIncidentDto" - } - } - } + "204": { + "description": "No Content" }, "400": { "description": "Bad request — the payload failed validation", @@ -18090,13 +20123,13 @@ } } }, - "/api/v1/status-pages/{id}/incidents/{incidentId}": { - "get": { + "/api/v1/status-pages/{id}/incidents/{incidentId}/dismiss": { + "post": { "tags": [ "Status Pages" ], - "summary": "Get incident details with timeline", - "operationId": "getIncident", + "summary": "Dismiss a draft incident (deletes it permanently)", + "operationId": "dismissIncident", "parameters": [ { "name": "id", @@ -18118,15 +20151,8 @@ } ], "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/SingleValueResponseStatusPageIncidentDto" - } - } - } + "204": { + "description": "No Content" }, "400": { "description": "Bad request — the payload failed validation", @@ -18209,13 +20235,15 @@ } } } - }, - "put": { + } + }, + "/api/v1/status-pages/{id}/incidents/{incidentId}/publish": { + "post": { "tags": [ "Status Pages" ], - "summary": "Update an incident", - "operationId": "updateIncident", + "summary": "Publish a draft incident (sets publishedAt, applies component statuses, notifies subscribers)", + "operationId": "publishIncident", "parameters": [ { "name": "id", @@ -18240,11 +20268,10 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/UpdateStatusPageIncidentRequest" + "$ref": "#/components/schemas/PublishStatusPageIncidentRequest" } } - }, - "required": true + } }, "responses": { "200": { @@ -18338,13 +20365,15 @@ } } } - }, - "delete": { + } + }, + "/api/v1/status-pages/{id}/incidents/{incidentId}/updates": { + "post": { "tags": [ "Status Pages" ], - "summary": "Delete an incident", - "operationId": "deleteIncident", + "summary": "Post an incident timeline update", + "operationId": "postIncidentUpdate", "parameters": [ { "name": "id", @@ -18365,9 +20394,26 @@ } } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateStatusPageIncidentUpdateRequest" + } + } + }, + "required": true + }, "responses": { - "204": { - "description": "No Content" + "201": { + "description": "Created", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/SingleValueResponseStatusPageIncidentDto" + } + } + } }, "400": { "description": "Bad request — the payload failed validation", @@ -18452,13 +20498,13 @@ } } }, - "/api/v1/status-pages/{id}/incidents/{incidentId}/dismiss": { - "post": { + "/api/v1/status-pages/{id}/layout/reorder": { + "put": { "tags": [ "Status Pages" ], - "summary": "Dismiss a draft incident (deletes it permanently)", - "operationId": "dismissIncident", + "summary": "Reorder page-level layout: groups and ungrouped components share one ordering", + "operationId": "reorderLayout", "parameters": [ { "name": "id", @@ -18468,17 +20514,18 @@ "type": "string", "format": "uuid" } - }, - { - "name": "incidentId", - "in": "path", - "required": true, - "schema": { - "type": "string", - "format": "uuid" - } } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReorderPageLayoutRequest" + } + } + }, + "required": true + }, "responses": { "204": { "description": "No Content" @@ -18566,13 +20613,14 @@ } } }, - "/api/v1/status-pages/{id}/incidents/{incidentId}/publish": { - "post": { + "/api/v1/status-pages/{id}/notification-deliveries": { + "get": { "tags": [ "Status Pages" ], - "summary": "Publish a draft incident (sets publishedAt, applies component statuses, notifies subscribers)", - "operationId": "publishIncident", + "summary": "List notification delivery receipts", + "description": "Returns delivery rows for this status page (newest first). Optional filters: incidentId, eventType.", + "operationId": "listNotificationDeliveries", "parameters": [ { "name": "id", @@ -18585,30 +20633,35 @@ }, { "name": "incidentId", - "in": "path", - "required": true, + "in": "query", + "required": false, "schema": { "type": "string", "format": "uuid" } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PublishStatusPageIncidentRequest" - } + }, + { + "name": "eventType", + "in": "query", + "required": false, + "schema": { + "type": "string", + "enum": [ + "SUBSCRIPTION_CONFIRMATION", + "INCIDENT_CREATED", + "INCIDENT_UPDATED", + "INCIDENT_RESOLVED" + ] } } - }, + ], "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseStatusPageIncidentDto" + "$ref": "#/components/schemas/TableValueResultStatusPageNotificationDeliveryDto" } } } @@ -18696,13 +20749,13 @@ } } }, - "/api/v1/status-pages/{id}/incidents/{incidentId}/updates": { - "post": { + "/api/v1/status-pages/{id}/notification-deliveries/{deliveryId}": { + "get": { "tags": [ "Status Pages" ], - "summary": "Post an incident timeline update", - "operationId": "postIncidentUpdate", + "summary": "Get a notification delivery receipt", + "operationId": "getNotificationDelivery", "parameters": [ { "name": "id", @@ -18714,7 +20767,7 @@ } }, { - "name": "incidentId", + "name": "deliveryId", "in": "path", "required": true, "schema": { @@ -18723,23 +20776,13 @@ } } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateStatusPageIncidentUpdateRequest" - } - } - }, - "required": true - }, "responses": { - "201": { - "description": "Created", + "200": { + "description": "OK", "content": { "*/*": { "schema": { - "$ref": "#/components/schemas/SingleValueResponseStatusPageIncidentDto" + "$ref": "#/components/schemas/SingleValueResponseStatusPageNotificationDeliveryDto" } } } @@ -18827,13 +20870,14 @@ } } }, - "/api/v1/status-pages/{id}/layout/reorder": { - "put": { + "/api/v1/status-pages/{id}/notification-deliveries/{deliveryId}/retry": { + "post": { "tags": [ "Status Pages" ], - "summary": "Reorder page-level layout: groups and ungrouped components share one ordering", - "operationId": "reorderLayout", + "summary": "Retry a failed notification delivery", + "description": "Queues a FAILED delivery for another attempt. Refuses terminal attempt_count (~5). Idempotent when already RETRY_PENDING.", + "operationId": "retryNotificationDelivery", "parameters": [ { "name": "id", @@ -18843,22 +20887,28 @@ "type": "string", "format": "uuid" } + }, + { + "name": "deliveryId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ReorderPageLayoutRequest" + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/SingleValueResponseStatusPageNotificationDeliveryDto" + } } } }, - "required": true - }, - "responses": { - "204": { - "description": "No Content" - }, "400": { "description": "Bad request — the payload failed validation", "content": { @@ -21613,6 +23663,30 @@ }, "components": { "schemas": { + "AcknowledgeAllIncidentsResponse": { + "required": [ + "acknowledged", + "skipped" + ], + "type": "object", + "properties": { + "acknowledged": { + "type": "array", + "description": "Dispatches successfully acknowledged in this request", + "items": { + "$ref": "#/components/schemas/NotificationDispatchDto" + } + }, + "skipped": { + "type": "array", + "description": "Dispatches skipped (already acked or not in an acknowledgeable state)", + "items": { + "$ref": "#/components/schemas/SkippedDispatch" + } + } + }, + "description": "Result of acknowledging all acknowledgeable dispatches for an incident" + }, "AcquireDeployLockRequest": { "required": [ "lockedBy" @@ -21723,16 +23797,42 @@ "description": "Request body for adding a member to a resource group" }, "AdminAddSubscriberRequest": { - "required": [ - "email" - ], "type": "object", "properties": { "email": { - "minLength": 1, + "maxLength": 320, + "minLength": 0, "type": "string", - "description": "Email address to add as a confirmed subscriber", - "format": "email" + "description": "Email for EMAIL channel; legacy clients may send only this", + "format": "email", + "nullable": true + }, + "channel": { + "type": "string", + "description": "Delivery channel (default: EMAIL)", + "nullable": true, + "enum": [ + "EMAIL", + "SMS", + "WEBHOOK" + ] + }, + "destination": { + "maxLength": 2048, + "minLength": 0, + "type": "string", + "description": "Channel destination (email, phone, or webhook URL)", + "nullable": true + }, + "componentIds": { + "type": "array", + "description": "Optional component IDs to scope; null means whole page", + "nullable": true, + "items": { + "type": "string", + "description": "Optional component IDs to scope; null means whole page", + "format": "uuid" + } } } }, @@ -21848,6 +23948,36 @@ "type": "string", "description": "Jira project key", "nullable": true + }, + "phoneNumber": { + "type": "string", + "description": "Recipient phone number in E.164 format (SMS / phone-call channels)", + "nullable": true + }, + "verifiedPhoneNumberId": { + "type": "integer", + "description": "Id of the org verified_phone_number row bound to this channel", + "format": "int64", + "nullable": true + }, + "phoneNumbers": { + "type": "array", + "description": "Deprecated mirror of phoneNumber as a length-1 list for older clients", + "nullable": true, + "items": { + "type": "string", + "description": "Deprecated mirror of phoneNumber as a length-1 list for older clients" + } + }, + "voiceLanguage": { + "type": "string", + "description": "BCP-47 voice language for phone-call TTS (e.g. en-US, de-DE)", + "nullable": true + }, + "preferredLanguage": { + "type": "string", + "description": "Preferred language for SMS/voice (BCP-47, e.g. en-US, de-DE)", + "nullable": true } }, "description": "Non-sensitive alert channel configuration metadata" @@ -21856,6 +23986,7 @@ "required": [ "channelType", "createdAt", + "enabled", "id", "name", "updatedAt" @@ -21894,7 +24025,9 @@ "zapier", "datadog", "jira", - "gitlab" + "gitlab", + "sms", + "phone_call" ] }, "displayConfig": { @@ -21905,6 +24038,10 @@ } ] }, + "enabled": { + "type": "boolean", + "description": "Whether this channel is enabled and will receive alerts" + }, "createdAt": { "type": "string", "description": "Timestamp when the channel was created", @@ -21998,7 +24135,11 @@ "DELIVERED", "RETRY_PENDING", "FAILED", - "CANCELLED" + "CANCELLED", + "SKIPPED_NO_CREDIT", + "SKIPPED_UNVERIFIED", + "SKIPPED_OPTED_OUT", + "SKIPPED_RATE_LIMITED" ] }, "eventType": { @@ -22845,7 +24986,8 @@ "tcp": "#/components/schemas/Tcp", "icmp": "#/components/schemas/Icmp", "dns": "#/components/schemas/Dns", - "mcp_server": "#/components/schemas/McpServer" + "mcp_server": "#/components/schemas/McpServer", + "code": "#/components/schemas/Code" } }, "oneOf": [ @@ -22863,9 +25005,95 @@ }, { "$ref": "#/components/schemas/McpServer" + }, + { + "$ref": "#/components/schemas/Code" } ] }, + "Code": { + "type": "object", + "description": "Code check (browser / multi-step API) specific details", + "properties": { + "check_type": { + "type": "string", + "enum": [ + "code" + ] + }, + "exitCode": { + "type": "integer", + "description": "Container exit code (0 = pass)", + "format": "int32" + }, + "stdoutSnippet": { + "type": "string", + "description": "Truncated stdout from the container", + "nullable": true + }, + "stderrSnippet": { + "type": "string", + "description": "Truncated stderr from the container", + "nullable": true + }, + "steps": { + "type": "array", + "description": "Named steps extracted from Playwright test output", + "nullable": true, + "items": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/CodeCheckStep" + } + ] + } + }, + "failureKind": { + "type": "string", + "description": "Failure classification: timeout, assertion, or error", + "nullable": true + }, + "timedOut": { + "type": "boolean", + "description": "Whether the run hit a step/total/run-budget timeout", + "nullable": true + } + }, + "required": [ + "check_type", + "exitCode" + ] + }, + "CodeCheckStep": { + "required": [ + "name", + "status" + ], + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Step name from test.step() or test() call" + }, + "status": { + "type": "string", + "description": "Step outcome: passed, failed, skipped, or timedOut" + }, + "durationMs": { + "type": "integer", + "description": "Step duration in milliseconds", + "format": "int32", + "nullable": true + }, + "error": { + "type": "string", + "description": "Error message if the step failed", + "nullable": true + } + }, + "description": "A single named step within a code check execution" + }, "ComponentImpact": { "required": [ "componentId", @@ -22934,6 +25162,35 @@ }, "description": "A single component position" }, + "ComponentSample": { + "required": [ + "componentId", + "newStatus" + ], + "type": "object", + "properties": { + "componentId": { + "type": "string", + "description": "Component ID", + "format": "uuid" + }, + "componentName": { + "type": "string", + "description": "Component display name", + "nullable": true + }, + "oldStatus": { + "type": "string", + "description": "Previous status before the flip", + "nullable": true + }, + "newStatus": { + "type": "string", + "description": "New status after the flip" + } + }, + "description": "One component sample inside a transition rollup" + }, "ComponentsSummaryDto": { "required": [ "groupComponentCounts", @@ -22986,6 +25243,33 @@ }, "description": "Current status of each active component" }, + "ComponentTransitionEventDto": { + "required": [ + "componentSample", + "newStatus", + "componentCount" + ], + "type": "object", + "properties": { + "newStatus": { + "type": "string", + "description": "New status that defines this rollup bucket" + }, + "componentCount": { + "type": "integer", + "description": "Total components in the 5-minute rollup bucket", + "format": "int32" + }, + "componentSample": { + "type": "array", + "description": "Up to 5 sample components from the bucket", + "items": { + "$ref": "#/components/schemas/ComponentSample" + } + } + }, + "description": "Rolled-up component status transitions for a status-events rail row" + }, "ComponentUptimeDayDto": { "required": [ "date", @@ -23143,6 +25427,9 @@ { "$ref": "#/components/schemas/PagerDutyChannelConfig" }, + { + "$ref": "#/components/schemas/PhoneCallChannelConfig" + }, { "$ref": "#/components/schemas/PushbulletChannelConfig" }, @@ -23155,6 +25442,9 @@ { "$ref": "#/components/schemas/SlackChannelConfig" }, + { + "$ref": "#/components/schemas/SmsChannelConfig" + }, { "$ref": "#/components/schemas/SplunkOnCallChannelConfig" }, @@ -23491,6 +25781,18 @@ "type": "string", "description": "Detailed description or context for the incident", "nullable": true + }, + "serviceId": { + "type": "string", + "description": "Vendor service to link; optional for Dependencies create CTA", + "format": "uuid", + "nullable": true + }, + "serviceIncidentId": { + "type": "string", + "description": "Vendor incident to link; idempotent if an active org incident already links it", + "format": "uuid", + "nullable": true } } }, @@ -23517,7 +25819,9 @@ "MCP_SERVER", "TCP", "ICMP", - "HEARTBEAT" + "HEARTBEAT", + "BROWSER", + "MULTI_STEP_API" ] }, "config": { @@ -23537,6 +25841,9 @@ { "$ref": "#/components/schemas/McpServerMonitorConfig" }, + { + "$ref": "#/components/schemas/ScriptMonitorConfig" + }, { "$ref": "#/components/schemas/TcpMonitorConfig" } @@ -23982,6 +26289,12 @@ "type": "boolean", "description": "Whether to email confirmed subscribers about this incident (default: true)", "nullable": true + }, + "monitoringIncidentId": { + "type": "string", + "description": "Monitoring incident ID to link this status page incident to; null for standalone", + "format": "uuid", + "nullable": true } } }, @@ -24175,6 +26488,72 @@ }, "description": "Create a new workspace within the organization" }, + "CreditPolicy": { + "type": "object", + "properties": { + "summary": { + "type": "string", + "description": "Brief summary of credit policy", + "nullable": true + }, + "maxCreditPercent": { + "type": "integer", + "description": "Max credit as percent of monthly fee", + "format": "int32", + "nullable": true + }, + "claimWindowDays": { + "type": "integer", + "description": "Days to submit a credit claim after eligibility", + "format": "int32", + "nullable": true + }, + "creditApplicationDays": { + "type": "integer", + "description": "Days for credit to be applied after approval", + "format": "int32", + "nullable": true + }, + "tiers": { + "type": "array", + "description": "Credit tiers by uptime threshold", + "nullable": true, + "items": { + "$ref": "#/components/schemas/CreditTier" + } + } + }, + "description": "Service credit policy for SLA violations" + }, + "CreditTier": { + "required": [ + "uptimeRange" + ], + "type": "object", + "properties": { + "uptimeRange": { + "type": "string", + "description": "Uptime range, e.g. '99.1% – 99.98%'" + }, + "creditPercent": { + "type": "integer", + "description": "Credit percent of monthly fee", + "format": "int32", + "nullable": true + }, + "formula": { + "type": "string", + "description": "Credit formula when percent is not a fixed number", + "nullable": true + }, + "notes": { + "type": "string", + "description": "Additional notes on this credit tier", + "nullable": true + } + }, + "description": "Credit tiers by uptime threshold" + }, "CursorPageCheckResultDto": { "required": [ "data", @@ -24201,6 +26580,32 @@ }, "description": "Cursor-paginated response for time-series and append-only data" }, + "CursorPageIncidentActivityEventDto": { + "required": [ + "data", + "hasMore" + ], + "type": "object", + "properties": { + "data": { + "type": "array", + "description": "Items on this page", + "items": { + "$ref": "#/components/schemas/IncidentActivityEventDto" + } + }, + "nextCursor": { + "type": "string", + "description": "Opaque cursor for the next page; null when there are no more results", + "nullable": true + }, + "hasMore": { + "type": "boolean", + "description": "Whether more results exist beyond this page" + } + }, + "description": "Cursor-paginated response for time-series and append-only data" + }, "CursorPageServiceCatalogDto": { "required": [ "data", @@ -24253,6 +26658,32 @@ }, "description": "Cursor-paginated response for time-series and append-only data" }, + "CursorPageStatusEventDto": { + "required": [ + "data", + "hasMore" + ], + "type": "object", + "properties": { + "data": { + "type": "array", + "description": "Items on this page", + "items": { + "$ref": "#/components/schemas/StatusEventDto" + } + }, + "nextCursor": { + "type": "string", + "description": "Opaque cursor for the next page; null when there are no more results", + "nullable": true + }, + "hasMore": { + "type": "boolean", + "description": "Whether more results exist beyond this page" + } + }, + "description": "Cursor-paginated response for time-series and append-only data" + }, "DashboardOverviewDto": { "required": [ "incidents", @@ -25806,6 +28237,58 @@ "warnMs" ] }, + "IncidentActivityEventDto": { + "required": [ + "at", + "id", + "kind", + "summary" + ], + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Stable event ID (source row ID)", + "format": "uuid" + }, + "at": { + "type": "string", + "description": "When the event occurred (ISO 8601)", + "format": "date-time" + }, + "kind": { + "type": "string", + "description": "Activity event kind in the merged incident activity stream", + "enum": [ + "update", + "dispatch", + "delivery", + "forensic_transition", + "status_page_update" + ] + }, + "actor": { + "type": "string", + "description": "Actor label when known (user email, system, etc.)", + "nullable": true + }, + "summary": { + "type": "string", + "description": "Human-readable summary of the event" + }, + "payload": { + "type": "object", + "additionalProperties": { + "type": "object", + "description": "Kind-specific structured fields", + "nullable": true + }, + "description": "Kind-specific structured fields", + "nullable": true + } + }, + "description": "Merged incident activity event (updates, dispatches, deliveries, forensics, SP updates)" + }, "IncidentDetailDto": { "required": [ "incident", @@ -25828,6 +28311,14 @@ "items": { "$ref": "#/components/schemas/LinkedStatusPageIncidentDto" } + }, + "trigger": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/IncidentTriggerDto" + } + ] } } }, @@ -25842,7 +28333,8 @@ "updatedAt", "organizationId", "reopenCount", - "statusPageVisible" + "statusPageVisible", + "suppressDispatch" ], "type": "object", "properties": { @@ -25925,6 +28417,10 @@ "type": "boolean", "description": "Whether this incident is visible on the status page" }, + "suppressDispatch": { + "type": "boolean", + "description": "When true, alert channels are suppressed (AWARENESS silent tracking); false means Alerted" + }, "serviceIncidentId": { "type": "string", "description": "Linked vendor service incident ID; null for monitor incidents", @@ -25966,6 +28462,11 @@ "AUTO_RESOLVED" ] }, + "resolutionNote": { + "type": "string", + "description": "Body from the most recent resolve update; null when not currently resolved, auto-resolved without a note, or no resolve update body was provided", + "nullable": true + }, "startedAt": { "type": "string", "description": "Timestamp when the incident was detected or created", @@ -26052,10 +28553,99 @@ "type": "string", "description": "Detection engine semver that evaluated the rule. Omitted from JSON when null, treat missing as null.", "nullable": true + }, + "displayKey": { + "type": "string", + "description": "Org-scoped human-readable incident code, e.g. \"ABC-42\". Null on incidents created by pre-INC-keys API pods before the sweep; treat missing as unknown and fall back to the id", + "nullable": true } }, "description": "Incident triggered by a monitor check failure or manual creation" }, + "IncidentEventDto": { + "required": [ + "incidentId", + "title" + ], + "type": "object", + "properties": { + "incidentId": { + "type": "string", + "description": "Vendor catalog incident ID", + "format": "uuid" + }, + "externalId": { + "type": "string", + "description": "Vendor-supplied external incident ID", + "nullable": true + }, + "title": { + "type": "string", + "description": "Incident title from the vendor status page" + }, + "impact": { + "type": "string", + "description": "Vendor impact level (major, minor, none)", + "nullable": true + }, + "status": { + "type": "string", + "description": "Vendor lifecycle status (only set on incident.update rows)", + "nullable": true + }, + "body": { + "type": "string", + "description": "Update body text (only set on incident.update rows)", + "nullable": true + }, + "shortlink": { + "type": "string", + "description": "Short public URL for the vendor incident", + "nullable": true + }, + "startedAt": { + "type": "string", + "description": "When the vendor incident started", + "format": "date-time", + "nullable": true + }, + "resolvedAt": { + "type": "string", + "description": "When the vendor incident resolved", + "format": "date-time", + "nullable": true + }, + "detectedAt": { + "type": "string", + "description": "When DevHelm first detected the incident", + "format": "date-time", + "nullable": true + }, + "vendorCreatedAt": { + "type": "string", + "description": "Vendor-reported creation timestamp", + "format": "date-time", + "nullable": true + }, + "durationSeconds": { + "type": "integer", + "description": "Total duration in seconds (set on incident.resolved)", + "format": "int64", + "nullable": true + }, + "affectedComponentIds": { + "type": "array", + "description": "Affected component IDs from the vendor incident join", + "nullable": true, + "items": { + "type": "string", + "description": "Affected component IDs from the vendor incident join", + "format": "uuid" + } + } + }, + "description": "Vendor incident fields for a status-events rail row" + }, "IncidentFilterParams": { "type": "object", "properties": { @@ -26122,6 +28712,12 @@ "format": "uuid", "nullable": true }, + "excludeId": { + "type": "string", + "description": "Exclude this incident ID from results (related-incident lists)", + "format": "uuid", + "nullable": true + }, "startedFrom": { "type": "string", "description": "Earliest startedAt to include (inclusive, ISO 8601)", @@ -26414,6 +29010,59 @@ } } }, + "IncidentTriggerDto": { + "required": [ + "source" + ], + "type": "object", + "properties": { + "ruleType": { + "type": "string", + "description": "Trigger rule type (consecutive_failures, failures_in_window, response_time); null when unknown", + "nullable": true + }, + "ruleIndex": { + "type": "integer", + "description": "0-based index into the policy trigger_rules array; null when unknown", + "format": "int32", + "nullable": true + }, + "count": { + "type": "integer", + "description": "Observed failing_streak or failures_in_window from forensics; null when unavailable", + "format": "int32", + "nullable": true + }, + "threshold": { + "type": "integer", + "description": "Rule required count or threshold_ms from forensics; null when unavailable", + "format": "int32", + "nullable": true + }, + "lastError": { + "type": "string", + "description": "failure_reason from the triggering check result; null when unavailable", + "nullable": true + }, + "firstFailedCheckAt": { + "type": "string", + "description": "Earliest failing check timestamp in the confirm window when computable; null otherwise", + "format": "date-time", + "nullable": true + }, + "source": { + "minLength": 1, + "type": "string", + "description": "Where the enrichment came from: forensics, checks, or none (STATUS_DATA/manual/no data)", + "enum": [ + "forensics", + "checks", + "none" + ] + } + }, + "description": "Honest trigger metadata for the incident origin tooltip / TTD strip" + }, "IncidentUpdateDto": { "required": [ "createdAt", @@ -26592,6 +29241,7 @@ }, "InviteDto": { "required": [ + "createdAt", "email", "expiresAt", "roleOffered", @@ -26617,6 +29267,11 @@ "MEMBER" ] }, + "createdAt": { + "type": "string", + "description": "Timestamp when the invite was created", + "format": "date-time" + }, "expiresAt": { "type": "string", "description": "Timestamp when the invite expires", @@ -26789,8 +29444,11 @@ }, "LinkedStatusPageIncidentDto": { "required": [ + "connectionMode", "id", "impact", + "pageIncidentMode", + "spIncidentId", "status", "statusPageId", "statusPageName", @@ -26802,23 +29460,34 @@ "properties": { "id": { "type": "string", + "description": "Status page incident ID (same value as spIncidentId; kept for backwards compatibility)", + "format": "uuid" + }, + "spIncidentId": { + "type": "string", + "description": "Status page incident ID (alias for id) — use this when the outer context is a monitoring incident", "format": "uuid" }, "statusPageId": { "type": "string", + "description": "Parent status page ID", "format": "uuid" }, "statusPageName": { - "type": "string" + "type": "string", + "description": "Parent status page display name" }, "statusPageSlug": { - "type": "string" + "type": "string", + "description": "Parent status page URL slug" }, "title": { - "type": "string" + "type": "string", + "description": "Customer-facing incident title" }, "status": { "type": "string", + "description": "Current lifecycle status (INVESTIGATING, IDENTIFIED, MONITORING, RESOLVED)", "enum": [ "INVESTIGATING", "IDENTIFIED", @@ -26828,6 +29497,7 @@ }, "impact": { "type": "string", + "description": "Impact level (NONE, MINOR, MAJOR, CRITICAL)", "enum": [ "NONE", "MINOR", @@ -26836,12 +29506,31 @@ ] }, "scheduled": { - "type": "boolean" + "type": "boolean", + "description": "Scheduled maintenance flag" }, "publishedAt": { "type": "string", + "description": "Publish time; null while draft", "format": "date-time", "nullable": true + }, + "connectionMode": { + "type": "string", + "description": "Whether the linked SPI was created by automation (AUTO) or by a human/API caller (MANUAL)", + "enum": [ + "AUTO", + "MANUAL" + ] + }, + "pageIncidentMode": { + "type": "string", + "description": "Incident mode of the parent status page at read time (MANUAL, REVIEW, AUTOMATIC)", + "enum": [ + "MANUAL", + "REVIEW", + "AUTOMATIC" + ] } } }, @@ -26869,6 +29558,79 @@ }, "description": "A component affected by a scheduled maintenance window" }, + "MaintenanceEventDto": { + "required": [ + "externalId", + "maintenanceId", + "status", + "title" + ], + "type": "object", + "properties": { + "maintenanceId": { + "type": "string", + "description": "Vendor catalog maintenance ID", + "format": "uuid" + }, + "externalId": { + "type": "string", + "description": "Vendor-supplied external maintenance ID" + }, + "title": { + "type": "string", + "description": "Maintenance title from the vendor status page" + }, + "status": { + "type": "string", + "description": "Lifecycle status: scheduled, in_progress, verifying, completed" + }, + "impact": { + "type": "string", + "description": "Vendor impact level", + "nullable": true + }, + "shortlink": { + "type": "string", + "description": "Short public URL for the vendor maintenance", + "nullable": true + }, + "scheduledFor": { + "type": "string", + "description": "Scheduled start; null for undated maintenance", + "format": "date-time", + "nullable": true + }, + "scheduledUntil": { + "type": "string", + "description": "Scheduled end", + "format": "date-time", + "nullable": true + }, + "startedAt": { + "type": "string", + "description": "When maintenance actually started", + "format": "date-time", + "nullable": true + }, + "completedAt": { + "type": "string", + "description": "When maintenance completed", + "format": "date-time", + "nullable": true + }, + "affectedComponentIds": { + "type": "array", + "description": "Affected component IDs", + "nullable": true, + "items": { + "type": "string", + "description": "Affected component IDs", + "format": "uuid" + } + } + }, + "description": "Vendor maintenance fields for a status-events rail row" + }, "MaintenanceUpdateDto": { "required": [ "id", @@ -27686,7 +30448,9 @@ "MCP_SERVER", "TCP", "ICMP", - "HEARTBEAT" + "HEARTBEAT", + "BROWSER", + "MULTI_STEP_API" ] }, "config": { @@ -27706,6 +30470,9 @@ { "$ref": "#/components/schemas/McpServerMonitorConfig" }, + { + "$ref": "#/components/schemas/ScriptMonitorConfig" + }, { "$ref": "#/components/schemas/TcpMonitorConfig" } @@ -27904,7 +30671,9 @@ "MCP_SERVER", "TCP", "ICMP", - "HEARTBEAT" + "HEARTBEAT", + "BROWSER", + "MULTI_STEP_API" ] }, "config": { @@ -27924,6 +30693,9 @@ { "$ref": "#/components/schemas/McpServerMonitorConfig" }, + { + "$ref": "#/components/schemas/ScriptMonitorConfig" + }, { "$ref": "#/components/schemas/TcpMonitorConfig" } @@ -28087,6 +30859,32 @@ }, "description": "Inline tag creation — creates the tag if it does not already exist" }, + "NoSlaContext": { + "type": "object", + "properties": { + "reason": { + "type": "string", + "description": "Reason no SLA is published", + "nullable": true + }, + "historicalClaim": { + "type": "string", + "description": "Non-binding historical uptime claim", + "nullable": true + }, + "supportSla": { + "type": "string", + "description": "Support response time SLA if different from uptime SLA", + "nullable": true + }, + "enterpriseNote": { + "type": "string", + "description": "Note about enterprise/custom SLA availability", + "nullable": true + } + }, + "description": "Context for vendors with no public SLA" + }, "NotificationDispatchDto": { "required": [ "createdAt", @@ -28159,6 +30957,25 @@ "format": "date-time", "nullable": true }, + "acknowledgedBy": { + "type": "string", + "description": "Actor who acknowledged this dispatch (user email, api-key:, voice:, etc.); null if not acknowledged", + "nullable": true + }, + "acknowledgedVia": { + "type": "string", + "description": "Channel used to acknowledge (DASHBOARD, API, PHONE_CALL, INTERNAL, etc.); null if not acknowledged", + "nullable": true + }, + "matchedRules": { + "type": "array", + "description": "Labels of match rules that caused this dispatch (same wording as TestMatchResult); null on pre-V138 rows; catch-all is [\"(catch-all: no rules defined)\"]", + "nullable": true, + "items": { + "type": "string", + "description": "Labels of match rules that caused this dispatch (same wording as TestMatchResult); null on pre-V138 rows; catch-all is [\"(catch-all: no rules defined)\"]" + } + }, "nextEscalationAt": { "type": "string", "description": "Timestamp when the next escalation step will fire (null if not scheduled)", @@ -28302,6 +31119,46 @@ }, "description": "Org-level notification policy with match rules and escalation chain" }, + "OfficialSla": { + "type": "object", + "properties": { + "percentage": { + "type": "string", + "description": "Advertised uptime percentage, e.g. '99.99%'", + "nullable": true + }, + "scope": { + "type": "string", + "description": "Scope of the SLA, e.g. 'Monthly uptime per region'", + "nullable": true + }, + "measurement": { + "type": "string", + "description": "How the vendor measures uptime for SLA purposes", + "nullable": true + }, + "exclusions": { + "type": "string", + "description": "Summary of exclusions from SLA calculation", + "nullable": true + }, + "appliesToPlans": { + "type": "array", + "description": "Plan names this SLA applies to, e.g. ['Enterprise']", + "nullable": true, + "items": { + "type": "string", + "description": "Plan names this SLA applies to, e.g. ['Enterprise']" + } + }, + "notCovered": { + "type": "string", + "description": "Services/components NOT covered by the SLA", + "nullable": true + } + }, + "description": "The vendor's officially advertised SLA commitment" + }, "OpsGenieChannelConfig": { "required": [ "channelType", @@ -28367,6 +31224,57 @@ }, "description": "Organization account details" }, + "OrgIncidentAnnotationDto": { + "required": [ + "incidentId", + "severity", + "status", + "alerted" + ], + "type": "object", + "properties": { + "incidentId": { + "type": "string", + "description": "Internal org incident ID", + "format": "uuid" + }, + "displayKey": { + "type": "string", + "description": "Human display key (e.g. DEV-42); null until platform INC codes ship", + "nullable": true + }, + "status": { + "type": "string", + "description": "Internal incident lifecycle status", + "enum": [ + "WATCHING", + "TRIGGERED", + "CONFIRMED", + "RESOLVED" + ] + }, + "severity": { + "type": "string", + "description": "Internal incident severity", + "enum": [ + "DOWN", + "DEGRADED", + "MAINTENANCE" + ] + }, + "alerted": { + "type": "boolean", + "description": "Whether alert channels were eligible to fire (false for AWARENESS silent tracking)" + }, + "startedAt": { + "type": "string", + "description": "When the internal incident started", + "format": "date-time", + "nullable": true + } + }, + "description": "Linked internal incident annotation on a vendor status-event row" + }, "OrgInfo": { "required": [ "name", @@ -28463,6 +31371,51 @@ "pageOrder" ] }, + "PhoneCallChannelConfig": { + "type": "object", + "properties": { + "channelType": { + "type": "string", + "enum": [ + "phone_call" + ] + }, + "phoneNumber": { + "type": "string", + "description": "Recipient phone number in E.164 format, e.g. +14155550123", + "nullable": true + }, + "verifiedPhoneNumberId": { + "type": "integer", + "description": "Id of an org verified_phone_number row; alternative to phoneNumber", + "format": "int64", + "nullable": true + }, + "phoneNumbers": { + "type": "array", + "description": "Deprecated: use phoneNumber. Accepted as a length-1 list for one release; ignored when phoneNumber or id is set", + "nullable": true, + "items": { + "type": "string", + "description": "Deprecated: use phoneNumber. Accepted as a length-1 list for one release; ignored when phoneNumber or id is set", + "nullable": true + } + }, + "voiceLanguage": { + "type": "string", + "description": "TTS voice language/locale (default: en-US). See VoiceLanguage for supported values", + "nullable": true + }, + "preferredLanguage": { + "type": "string", + "description": "Preferred language for TTS and notifications (BCP-47, e.g. en-US, de-DE). Alias for voiceLanguage", + "nullable": true + } + }, + "required": [ + "channelType" + ] + }, "PlanInfo": { "required": [ "entitlements", @@ -28595,6 +31548,29 @@ }, "description": "Aggregated poll metrics for a time bucket" }, + "PricingTier": { + "required": [ + "name" + ], + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Tier name, e.g. 'Free', 'Pro', 'Enterprise'" + }, + "slaPercentage": { + "type": "string", + "description": "SLA percentage for this tier, e.g. '99.9%'", + "nullable": true + }, + "priceFrom": { + "type": "string", + "description": "Starting price, e.g. '$0', '$25/mo', 'Custom'", + "nullable": true + } + }, + "description": "Pricing tiers with associated SLA levels" + }, "PublishStatusPageIncidentRequest": { "type": "object", "properties": { @@ -28871,6 +31847,28 @@ }, "description": "Latest check result for a single region" }, + "RelatedIncidentsResponse": { + "required": [ + "data", + "total" + ], + "type": "object", + "properties": { + "data": { + "type": "array", + "description": "Related incident rows (newest first, capped by limit)", + "items": { + "$ref": "#/components/schemas/IncidentDto" + } + }, + "total": { + "type": "integer", + "description": "Total matching incidents in the window, excluding the current incident", + "format": "int64" + } + }, + "description": "Related incidents sharing the same origin within a time window" + }, "RemoveMonitorTagsRequest": { "required": [ "tagIds" @@ -29601,6 +32599,28 @@ }, "description": "A scheduled maintenance window from a vendor status page" }, + "ScriptMonitorConfig": { + "required": [ + "script" + ], + "type": "object", + "properties": { + "script": { + "maxLength": 65536, + "minLength": 1, + "type": "string", + "description": "Playwright test script source code" + }, + "timeoutSeconds": { + "maximum": 120, + "minimum": 5, + "type": "integer", + "description": "Maximum execution time in seconds (5–120)", + "format": "int32", + "nullable": true + } + } + }, "SecretDto": { "required": [ "createdAt", @@ -29672,6 +32692,34 @@ }, "description": "Admin-editable SEO metadata for pSEO pages" }, + "ServiceBreakdown": { + "required": [ + "service" + ], + "type": "object", + "properties": { + "service": { + "type": "string", + "description": "Sub-service name, e.g. 'EC2', 'S3'" + }, + "slaPercentage": { + "type": "string", + "description": "SLA percentage for this sub-service", + "nullable": true + }, + "scope": { + "type": "string", + "description": "Scope qualifier, e.g. 'Region (Multi-AZ)'", + "nullable": true + }, + "notes": { + "type": "string", + "description": "Additional notes on measurement or conditions", + "nullable": true + } + }, + "description": "Per-service breakdown for vendors with per_service SLA type" + }, "ServiceCatalogDto": { "required": [ "adapterType", @@ -29685,6 +32733,7 @@ "pollingIntervalSeconds", "enabled", "published", + "slaPublished", "componentCount", "activeIncidentCount" ], @@ -29739,6 +32788,10 @@ "published": { "type": "boolean" }, + "slaPublished": { + "type": "boolean", + "description": "Whether the service's SLA page is publicly visible" + }, "overallStatus": { "type": "string", "nullable": true @@ -29959,7 +33012,8 @@ "slug", "updatedAt", "pollingIntervalSeconds", - "enabled" + "enabled", + "slaPublished" ], "type": "object", "properties": { @@ -30062,6 +33116,10 @@ "dataCompleteness": { "type": "string" }, + "slaPublished": { + "type": "boolean", + "description": "Whether the service's SLA page is publicly visible" + }, "seoMetadata": { "nullable": true, "allOf": [ @@ -30070,6 +33128,14 @@ } ] }, + "slaData": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/SlaDataDto" + } + ] + }, "relatedServices": { "type": "array", "nullable": true, @@ -30128,6 +33194,13 @@ "type": "string" } }, + "affectedRegions": { + "type": "array", + "nullable": true, + "items": { + "type": "string" + } + }, "updates": { "type": "array", "items": { @@ -30203,6 +33276,13 @@ "type": "string", "format": "date-time", "nullable": true + }, + "affectedRegions": { + "type": "array", + "nullable": true, + "items": { + "type": "string" + } } } }, @@ -30566,6 +33646,19 @@ }, "description": "Replace the alert channels linked to a monitor" }, + "SetEnabledRequest": { + "required": [ + "enabled" + ], + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Whether the resource should be enabled" + } + }, + "description": "Request body for toggling a resource's enabled state" + }, "SetMonitorAuthRequest": { "required": [ "config" @@ -30590,6 +33683,49 @@ } } }, + "SetStatusPageComponentOverrideRequest": { + "required": [ + "expiresAt", + "status" + ], + "type": "object", + "properties": { + "status": { + "type": "string", + "description": "Override status while active; takes precedence over binding until expiry/clear", + "enum": [ + "OPERATIONAL", + "DEGRADED_PERFORMANCE", + "PARTIAL_OUTAGE", + "MAJOR_OUTAGE", + "UNDER_MAINTENANCE" + ] + }, + "reason": { + "maxLength": 2000, + "minLength": 0, + "type": "string", + "description": "Optional operator reason shown in the builder", + "nullable": true + }, + "expiresAt": { + "type": "string", + "description": "When the override expires (must be in the future, at most 24h from now)", + "format": "date-time" + } + } + }, + "SingleValueResponseAcknowledgeAllIncidentsResponse": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/AcknowledgeAllIncidentsResponse" + } + } + }, "SingleValueResponseAlertChannelDto": { "required": [ "data" @@ -31101,6 +34237,28 @@ } } }, + "SingleValueResponseStatusPageMeasuredComponentUptimeDto": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/StatusPageMeasuredComponentUptimeDto" + } + } + }, + "SingleValueResponseStatusPageNotificationDeliveryDto": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/StatusPageNotificationDeliveryDto" + } + } + }, "SingleValueResponseStatusPageSubscriberDto": { "required": [ "data" @@ -31211,6 +34369,39 @@ } } }, + "SkippedDispatch": { + "required": [ + "id", + "reason", + "status" + ], + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Dispatch identifier", + "format": "uuid" + }, + "status": { + "type": "string", + "description": "Current dispatch status", + "enum": [ + "PENDING", + "DISPATCHING", + "DELIVERED", + "ESCALATING", + "ACKNOWLEDGED", + "COMPLETED" + ] + }, + "reason": { + "minLength": 1, + "type": "string", + "description": "Why this dispatch was skipped" + } + }, + "description": "A dispatch that was not acknowledged by ack-all" + }, "SlackChannelConfig": { "required": [ "channelType", @@ -31236,6 +34427,146 @@ } } }, + "SlaDataDto": { + "type": "object", + "properties": { + "slaType": { + "type": "string", + "description": "SLA pattern: plan_gated, per_service, no_public_sla, or universal", + "nullable": true + }, + "officialSla": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/OfficialSla" + } + ] + }, + "serviceBreakdown": { + "type": "array", + "description": "Per-service breakdown for vendors with per_service SLA type", + "nullable": true, + "items": { + "$ref": "#/components/schemas/ServiceBreakdown" + } + }, + "pricingTiers": { + "type": "array", + "description": "Pricing tiers with associated SLA levels", + "nullable": true, + "items": { + "$ref": "#/components/schemas/PricingTier" + } + }, + "creditPolicy": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/CreditPolicy" + } + ] + }, + "noSlaContext": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/NoSlaContext" + } + ] + }, + "sourceUrls": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/SourceUrls" + } + ] + }, + "lastResearched": { + "type": "string", + "description": "ISO date when this data was last manually researched", + "nullable": true + }, + "researchNotes": { + "type": "string", + "description": "Freeform operator notes about the research", + "nullable": true + } + }, + "description": "Researched vendor SLA/pricing data for pSEO SLA report pages" + }, + "SmsChannelConfig": { + "type": "object", + "properties": { + "channelType": { + "type": "string", + "enum": [ + "sms" + ] + }, + "phoneNumber": { + "type": "string", + "description": "Recipient phone number in E.164 format, e.g. +14155550123", + "nullable": true + }, + "verifiedPhoneNumberId": { + "type": "integer", + "description": "Id of an org verified_phone_number row; alternative to phoneNumber", + "format": "int64", + "nullable": true + }, + "phoneNumbers": { + "type": "array", + "description": "Deprecated: use phoneNumber. Accepted as a length-1 list for one release; ignored when phoneNumber or id is set", + "nullable": true, + "items": { + "type": "string", + "description": "Deprecated: use phoneNumber. Accepted as a length-1 list for one release; ignored when phoneNumber or id is set", + "nullable": true + } + }, + "preferredLanguage": { + "type": "string", + "description": "Preferred language for SMS body (BCP-47, e.g. en-US, de-DE). Default: en-US", + "nullable": true + } + }, + "required": [ + "channelType" + ] + }, + "SourceUrls": { + "type": "object", + "properties": { + "slaPage": { + "type": "string", + "description": "URL to vendor's SLA page", + "nullable": true + }, + "pricingPage": { + "type": "string", + "description": "URL to vendor's pricing page", + "nullable": true + }, + "tosPage": { + "type": "string", + "description": "URL to vendor's Terms of Service", + "nullable": true + }, + "statusPage": { + "type": "string", + "description": "URL to vendor's status page", + "nullable": true + }, + "allSlasPage": { + "type": "string", + "description": "URL to vendor's all-services SLA listing", + "nullable": true + } + }, + "description": "Source URLs for SLA, pricing, and ToS pages" + }, "SplunkOnCallChannelConfig": { "required": [ "channelType", @@ -31332,6 +34663,72 @@ } } }, + "StatusEventDto": { + "required": [ + "at", + "id", + "type" + ], + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Stable row ID (incident/update/maintenance UUID or transition bucket key)", + "format": "uuid" + }, + "type": { + "type": "string", + "description": "Status event row type on the Dependencies Detail rail", + "enum": [ + "incident.opened", + "incident.update", + "incident.resolved", + "maintenance.scheduled", + "maintenance.started", + "maintenance.completed", + "component.transition" + ] + }, + "at": { + "type": "string", + "description": "Canonical timestamp used for reverse-chronological ordering", + "format": "date-time" + }, + "incident": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/IncidentEventDto" + } + ] + }, + "maintenance": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/MaintenanceEventDto" + } + ] + }, + "component": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/ComponentTransitionEventDto" + } + ] + }, + "orgAnnotation": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/OrgIncidentAnnotationDto" + } + ] + } + }, + "description": "Curated vendor status-event row for the Dependencies Detail rail" + }, "StatusPageBranding": { "type": "object", "properties": { @@ -31497,6 +34894,19 @@ }, "currentStatus": { "type": "string", + "description": "Effective display status (incident > active override > binding)", + "enum": [ + "OPERATIONAL", + "DEGRADED_PERFORMANCE", + "PARTIAL_OUTAGE", + "MAJOR_OUTAGE", + "UNDER_MAINTENANCE" + ] + }, + "overrideStatus": { + "type": "string", + "description": "Active timed override status; null when unset or expired", + "nullable": true, "enum": [ "OPERATIONAL", "DEGRADED_PERFORMANCE", @@ -31505,6 +34915,23 @@ "UNDER_MAINTENANCE" ] }, + "overrideReason": { + "type": "string", + "description": "Optional operator reason for the active override", + "nullable": true + }, + "overrideExpiresAt": { + "type": "string", + "description": "When the active override expires; null when unset or expired", + "format": "date-time", + "nullable": true + }, + "overrideActor": { + "type": "integer", + "description": "User id who set the override; null for API-key actors or when inactive", + "format": "int32", + "nullable": true + }, "showUptime": { "type": "boolean" }, @@ -31968,10 +35395,195 @@ } } }, + "StatusPageMeasuredComponentUptimeDto": { + "required": [ + "componentId", + "days", + "monitorId", + "source" + ], + "type": "object", + "properties": { + "source": { + "type": "string", + "description": "Uptime source discriminator; always measured for this resource", + "enum": [ + "incident_window", + "measured" + ] + }, + "componentId": { + "type": "string", + "description": "Status-page component ID", + "format": "uuid" + }, + "monitorId": { + "type": "string", + "description": "Linked monitor whose check rollups feed this series", + "format": "uuid" + }, + "trackingSince": { + "type": "string", + "description": "ISO-8601 date bars start (Camp A tracking-since); null only if unresolved", + "nullable": true + }, + "days": { + "type": "array", + "description": "Dense daily buckets from tracking start through today (oldest → newest)", + "items": { + "$ref": "#/components/schemas/StatusPageMeasuredUptimeDayDto" + } + } + }, + "description": "Measured (check-based) daily uptime for a MONITOR status-page component" + }, + "StatusPageMeasuredUptimeDayDto": { + "required": [ + "date", + "totalChecks", + "passedChecks" + ], + "type": "object", + "properties": { + "date": { + "type": "string", + "description": "Start-of-day timestamp for this bucket (UTC midnight, ISO 8601)", + "format": "date-time" + }, + "totalChecks": { + "type": "integer", + "description": "Total probe checks recorded that day across regions", + "format": "int64" + }, + "passedChecks": { + "type": "integer", + "description": "Checks that passed that day across regions", + "format": "int64" + }, + "uptimePercentage": { + "type": "number", + "description": "passedChecks / totalChecks × 100; null when totalChecks is 0", + "format": "double", + "nullable": true + } + }, + "description": "One UTC day of measured (check-based) uptime for a MONITOR status-page component" + }, + "StatusPageNotificationDeliveryDto": { + "required": [ + "channel", + "createdAt", + "eventType", + "id", + "status", + "statusPageId", + "subscriberId", + "attemptCount" + ], + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Delivery receipt ID", + "format": "uuid" + }, + "statusPageId": { + "type": "string", + "description": "Status page that owns this delivery", + "format": "uuid" + }, + "subscriberId": { + "type": "string", + "description": "Subscriber this delivery targeted", + "format": "uuid" + }, + "destination": { + "type": "string", + "description": "Subscriber destination (email, phone, or webhook URL)", + "nullable": true + }, + "channel": { + "type": "string", + "description": "Delivery channel from the subscriber (EMAIL, SMS, WEBHOOK)" + }, + "incidentId": { + "type": "string", + "description": "Related status-page incident ID, if any", + "format": "uuid", + "nullable": true + }, + "incidentUpdateId": { + "type": "string", + "description": "Related incident update ID, if any", + "format": "uuid", + "nullable": true + }, + "eventType": { + "type": "string", + "description": "Notification event type that triggered this delivery", + "enum": [ + "SUBSCRIPTION_CONFIRMATION", + "INCIDENT_CREATED", + "INCIDENT_UPDATED", + "INCIDENT_RESOLVED" + ] + }, + "status": { + "type": "string", + "description": "Current delivery status", + "enum": [ + "PENDING", + "DELIVERED", + "RETRY_PENDING", + "FAILED", + "CANCELLED", + "SKIPPED_NO_CREDIT", + "SKIPPED_UNVERIFIED", + "SKIPPED_OPTED_OUT", + "SKIPPED_RATE_LIMITED" + ] + }, + "attemptCount": { + "type": "integer", + "description": "Number of delivery attempts made", + "format": "int32" + }, + "lastAttemptAt": { + "type": "string", + "description": "When the last attempt was made", + "format": "date-time", + "nullable": true + }, + "nextRetryAt": { + "type": "string", + "description": "When the next retry is scheduled; null if not retrying", + "format": "date-time", + "nullable": true + }, + "deliveredAt": { + "type": "string", + "description": "When delivery was confirmed; null if not delivered", + "format": "date-time", + "nullable": true + }, + "errorMessage": { + "type": "string", + "description": "Error summary from the last failed attempt", + "nullable": true + }, + "createdAt": { + "type": "string", + "description": "When the delivery row was created", + "format": "date-time" + } + }, + "description": "Delivery receipt for a status page subscriber notification" + }, "StatusPageSubscriberDto": { "required": [ + "channel", "createdAt", - "email", + "destination", "id", "confirmed" ], @@ -31979,16 +35591,44 @@ "properties": { "id": { "type": "string", + "description": "Subscriber id", "format": "uuid" }, "email": { - "type": "string" + "type": "string", + "description": "Email when channel is EMAIL; null for other channels", + "nullable": true + }, + "channel": { + "type": "string", + "description": "Delivery channel (EMAIL, SMS, WEBHOOK)", + "enum": [ + "EMAIL", + "SMS", + "WEBHOOK" + ] + }, + "destination": { + "type": "string", + "description": "Channel destination (email, phone, or webhook URL)" + }, + "componentIds": { + "type": "array", + "description": "Scoped component IDs; null means whole page", + "nullable": true, + "items": { + "type": "string", + "description": "Scoped component IDs; null means whole page", + "format": "uuid" + } }, "confirmed": { - "type": "boolean" + "type": "boolean", + "description": "Whether the subscriber has confirmed opt-in" }, "createdAt": { "type": "string", + "description": "When the subscriber was created", "format": "date-time" } } @@ -33008,6 +36648,38 @@ } } }, + "TableValueResultStatusPageNotificationDeliveryDto": { + "required": [ + "data", + "hasNext", + "hasPrev" + ], + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/StatusPageNotificationDeliveryDto" + } + }, + "hasNext": { + "type": "boolean" + }, + "hasPrev": { + "type": "boolean" + }, + "totalElements": { + "type": "integer", + "format": "int64", + "nullable": true + }, + "totalPages": { + "type": "integer", + "format": "int32", + "nullable": true + } + } + }, "TableValueResultStatusPageSubscriberDto": { "required": [ "data", @@ -33072,6 +36744,70 @@ } } }, + "TableValueResultTestChannelResult": { + "required": [ + "data", + "hasNext", + "hasPrev" + ], + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TestChannelResult" + } + }, + "hasNext": { + "type": "boolean" + }, + "hasPrev": { + "type": "boolean" + }, + "totalElements": { + "type": "integer", + "format": "int64", + "nullable": true + }, + "totalPages": { + "type": "integer", + "format": "int32", + "nullable": true + } + } + }, + "TableValueResultVoiceLanguageDto": { + "required": [ + "data", + "hasNext", + "hasPrev" + ], + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/VoiceLanguageDto" + } + }, + "hasNext": { + "type": "boolean" + }, + "hasPrev": { + "type": "boolean" + }, + "totalElements": { + "type": "integer", + "format": "int64", + "nullable": true + }, + "totalPages": { + "type": "integer", + "format": "int32", + "nullable": true + } + } + }, "TableValueResultWebhookDeliveryDto": { "required": [ "data", @@ -33413,6 +37149,9 @@ { "$ref": "#/components/schemas/PagerDutyChannelConfig" }, + { + "$ref": "#/components/schemas/PhoneCallChannelConfig" + }, { "$ref": "#/components/schemas/PushbulletChannelConfig" }, @@ -33425,6 +37164,9 @@ { "$ref": "#/components/schemas/SlackChannelConfig" }, + { + "$ref": "#/components/schemas/SmsChannelConfig" + }, { "$ref": "#/components/schemas/SplunkOnCallChannelConfig" }, @@ -33491,6 +37233,29 @@ }, "description": "Result of a dry-run match evaluation against a notification policy" }, + "TestMonitorNotificationsRequest": { + "type": "object", + "properties": { + "channelIds": { + "type": "array", + "description": "Channel IDs to test; null or empty tests all channels attached to the monitor", + "nullable": true, + "items": { + "type": "string", + "description": "Channel IDs to test; null or empty tests all channels attached to the monitor", + "format": "uuid" + } + }, + "includeResolved": { + "type": "boolean", + "description": "Whether to include a resolved notification in the test (default: false)" + } + }, + "description": "Request to send test notifications through a monitor's alert channels", + "required": [ + "includeResolved" + ] + }, "TestNotificationPolicyRequest": { "type": "object", "properties": { @@ -33564,7 +37329,7 @@ "properties": { "dns_ms": { "type": "integer", - "description": "DNS resolution time in milliseconds", + "description": "Legacy DNS phase; null for new checks (no longer measured)", "format": "int32", "nullable": true, "example": 12 @@ -33753,64 +37518,70 @@ "config": { "oneOf": [ { - "$ref": "#/components/schemas/DatadogChannelConfig" + "$ref": "#/components/schemas/UpdateDatadogChannelConfig" }, { - "$ref": "#/components/schemas/DiscordChannelConfig" + "$ref": "#/components/schemas/UpdateDiscordChannelConfig" }, { - "$ref": "#/components/schemas/EmailChannelConfig" + "$ref": "#/components/schemas/UpdateEmailChannelConfig" }, { - "$ref": "#/components/schemas/GitLabChannelConfig" + "$ref": "#/components/schemas/UpdateGitLabChannelConfig" }, { - "$ref": "#/components/schemas/GoogleChatChannelConfig" + "$ref": "#/components/schemas/UpdateGoogleChatChannelConfig" }, { - "$ref": "#/components/schemas/IncidentIoChannelConfig" + "$ref": "#/components/schemas/UpdateIncidentIoChannelConfig" }, { - "$ref": "#/components/schemas/JiraChannelConfig" + "$ref": "#/components/schemas/UpdateJiraChannelConfig" }, { - "$ref": "#/components/schemas/LinearChannelConfig" + "$ref": "#/components/schemas/UpdateLinearChannelConfig" }, { - "$ref": "#/components/schemas/MattermostChannelConfig" + "$ref": "#/components/schemas/UpdateMattermostChannelConfig" }, { - "$ref": "#/components/schemas/OpsGenieChannelConfig" + "$ref": "#/components/schemas/UpdateOpsGenieChannelConfig" }, { - "$ref": "#/components/schemas/PagerDutyChannelConfig" + "$ref": "#/components/schemas/UpdatePagerDutyChannelConfig" }, { - "$ref": "#/components/schemas/PushbulletChannelConfig" + "$ref": "#/components/schemas/UpdatePhoneCallChannelConfig" }, { - "$ref": "#/components/schemas/PushoverChannelConfig" + "$ref": "#/components/schemas/UpdatePushbulletChannelConfig" }, { - "$ref": "#/components/schemas/RootlyChannelConfig" + "$ref": "#/components/schemas/UpdatePushoverChannelConfig" }, { - "$ref": "#/components/schemas/SlackChannelConfig" + "$ref": "#/components/schemas/UpdateRootlyChannelConfig" }, { - "$ref": "#/components/schemas/SplunkOnCallChannelConfig" + "$ref": "#/components/schemas/UpdateSlackChannelConfig" }, { - "$ref": "#/components/schemas/TeamsChannelConfig" + "$ref": "#/components/schemas/UpdateSmsChannelConfig" }, { - "$ref": "#/components/schemas/TelegramChannelConfig" + "$ref": "#/components/schemas/UpdateSplunkOnCallChannelConfig" }, { - "$ref": "#/components/schemas/WebhookChannelConfig" + "$ref": "#/components/schemas/UpdateTeamsChannelConfig" }, { - "$ref": "#/components/schemas/ZapierChannelConfig" + "$ref": "#/components/schemas/UpdateTelegramChannelConfig" + }, + { + "$ref": "#/components/schemas/UpdateWebhookChannelConfig" + }, + { + "$ref": "#/components/schemas/UpdateZapierChannelConfig" } ] }, @@ -33825,6 +37596,11 @@ "MCP", "API" ] + }, + "enabled": { + "type": "boolean", + "description": "Whether this channel is enabled (default: true); null preserves current value", + "nullable": true } } }, @@ -34004,6 +37780,84 @@ } } }, + "UpdateDatadogChannelConfig": { + "type": "object", + "properties": { + "channelType": { + "type": "string", + "enum": [ + "datadog" + ] + }, + "apiKey": { + "type": "string", + "description": "Datadog API key", + "nullable": true + }, + "site": { + "type": "string", + "description": "Datadog site region (e.g. datadoghq.com, datadoghq.eu, us3.datadoghq.com)", + "nullable": true + }, + "tags": { + "type": "string", + "description": "Comma-separated tags to attach to events", + "nullable": true + } + }, + "required": [ + "channelType" + ] + }, + "UpdateDiscordChannelConfig": { + "type": "object", + "properties": { + "channelType": { + "type": "string", + "enum": [ + "discord" + ] + }, + "webhookUrl": { + "type": "string", + "description": "Discord webhook URL", + "nullable": true + }, + "mentionRoleId": { + "type": "string", + "description": "Optional Discord role ID to mention in notifications", + "nullable": true + } + }, + "required": [ + "channelType" + ] + }, + "UpdateEmailChannelConfig": { + "required": [ + "channelType", + "recipients" + ], + "type": "object", + "properties": { + "channelType": { + "type": "string", + "enum": [ + "email" + ] + }, + "recipients": { + "minItems": 1, + "type": "array", + "description": "Email addresses to send notifications to", + "items": { + "type": "string", + "description": "Email addresses to send notifications to", + "format": "email" + } + } + } + }, "UpdateEnvironmentRequest": { "type": "object", "properties": { @@ -34031,6 +37885,79 @@ } } }, + "UpdateGitLabChannelConfig": { + "required": [ + "channelType", + "endpointUrl" + ], + "type": "object", + "properties": { + "channelType": { + "type": "string", + "enum": [ + "gitlab" + ] + }, + "endpointUrl": { + "minLength": 1, + "type": "string", + "description": "GitLab alert integration endpoint URL" + }, + "authorizationKey": { + "type": "string", + "description": "Authorization key from GitLab alert integration settings", + "nullable": true + } + } + }, + "UpdateGoogleChatChannelConfig": { + "type": "object", + "properties": { + "channelType": { + "type": "string", + "enum": [ + "google_chat" + ] + }, + "webhookUrl": { + "type": "string", + "description": "Google Chat space webhook URL", + "nullable": true + } + }, + "required": [ + "channelType" + ] + }, + "UpdateIncidentIoChannelConfig": { + "type": "object", + "properties": { + "channelType": { + "type": "string", + "enum": [ + "incident_io" + ] + }, + "apiKey": { + "type": "string", + "description": "incident.io API key with 'Create incidents' permission", + "nullable": true + }, + "severityId": { + "type": "string", + "description": "Severity ID for created incidents (from List Severities API)", + "nullable": true + }, + "visibility": { + "type": "string", + "description": "Incident visibility: public or private (default: public)", + "nullable": true + } + }, + "required": [ + "channelType" + ] + }, "UpdateIncidentPolicyRequest": { "required": [ "confirmation", @@ -34056,6 +37983,100 @@ }, "description": "Request body for updating an incident policy" }, + "UpdateIncidentRequest": { + "type": "object", + "properties": { + "title": { + "maxLength": 2147483647, + "minLength": 1, + "type": "string", + "description": "New title; null preserves current (min 1 char if present)", + "nullable": true + }, + "severity": { + "type": "string", + "description": "New severity: DOWN, DEGRADED, or MAINTENANCE; null preserves current", + "nullable": true, + "enum": [ + "DOWN", + "DEGRADED", + "MAINTENANCE" + ] + } + } + }, + "UpdateJiraChannelConfig": { + "required": [ + "channelType", + "domain", + "email", + "projectKey" + ], + "type": "object", + "properties": { + "channelType": { + "type": "string", + "enum": [ + "jira" + ] + }, + "domain": { + "minLength": 1, + "type": "string", + "description": "Atlassian instance domain (e.g. yourteam.atlassian.net)" + }, + "email": { + "minLength": 1, + "type": "string", + "description": "Atlassian account email for API authentication" + }, + "apiToken": { + "type": "string", + "description": "Atlassian API token", + "nullable": true + }, + "projectKey": { + "minLength": 1, + "type": "string", + "description": "Jira project key where issues are created (e.g. OPS)" + }, + "issueType": { + "type": "string", + "description": "Issue type name (e.g. Bug, Task, Incident)", + "nullable": true + } + } + }, + "UpdateLinearChannelConfig": { + "required": [ + "channelType", + "teamId" + ], + "type": "object", + "properties": { + "channelType": { + "type": "string", + "enum": [ + "linear" + ] + }, + "apiKey": { + "type": "string", + "description": "Linear API key", + "nullable": true + }, + "teamId": { + "minLength": 1, + "type": "string", + "description": "Team ID to create issues in" + }, + "labelId": { + "type": "string", + "description": "Label ID to attach to created issues", + "nullable": true + } + } + }, "UpdateMaintenanceWindowRequest": { "required": [ "endsAt", @@ -34100,6 +38121,35 @@ } } }, + "UpdateMattermostChannelConfig": { + "type": "object", + "properties": { + "channelType": { + "type": "string", + "enum": [ + "mattermost" + ] + }, + "webhookUrl": { + "type": "string", + "description": "Mattermost incoming webhook URL", + "nullable": true + }, + "channel": { + "type": "string", + "description": "Override channel (if webhook allows)", + "nullable": true + }, + "iconUrl": { + "type": "string", + "description": "Custom bot icon URL", + "nullable": true + } + }, + "required": [ + "channelType" + ] + }, "UpdateMonitorAuthRequest": { "required": [ "config" @@ -34152,6 +38202,9 @@ { "$ref": "#/components/schemas/McpServerMonitorConfig" }, + { + "$ref": "#/components/schemas/ScriptMonitorConfig" + }, { "$ref": "#/components/schemas/TcpMonitorConfig" } @@ -34291,6 +38344,30 @@ }, "description": "Request body for updating a notification policy (null fields are preserved)" }, + "UpdateOpsGenieChannelConfig": { + "type": "object", + "properties": { + "channelType": { + "type": "string", + "enum": [ + "opsgenie" + ] + }, + "apiKey": { + "type": "string", + "description": "OpsGenie API key for alert creation", + "nullable": true + }, + "region": { + "type": "string", + "description": "OpsGenie API region: us or eu", + "nullable": true + } + }, + "required": [ + "channelType" + ] + }, "UpdateOrgDetailsRequest": { "required": [ "email", @@ -34333,6 +38410,133 @@ } } }, + "UpdatePagerDutyChannelConfig": { + "type": "object", + "properties": { + "channelType": { + "type": "string", + "enum": [ + "pagerduty" + ] + }, + "routingKey": { + "type": "string", + "description": "PagerDuty Events API v2 routing (integration) key", + "nullable": true + }, + "severityOverride": { + "type": "string", + "description": "Override PagerDuty severity mapping", + "nullable": true + } + }, + "required": [ + "channelType" + ] + }, + "UpdatePhoneCallChannelConfig": { + "type": "object", + "properties": { + "channelType": { + "type": "string", + "enum": [ + "phone_call" + ] + }, + "phoneNumber": { + "type": "string", + "description": "Recipient phone number in E.164 format; null preserves current", + "nullable": true + }, + "verifiedPhoneNumberId": { + "type": "integer", + "description": "Id of an org verified_phone_number row; null preserves current when phoneNumber also null", + "format": "int64", + "nullable": true + }, + "phoneNumbers": { + "type": "array", + "description": "Deprecated: use phoneNumber", + "nullable": true, + "items": { + "type": "string", + "description": "Deprecated: use phoneNumber", + "nullable": true + } + }, + "voiceLanguage": { + "type": "string", + "description": "TTS voice language/locale (default: en-US). See VoiceLanguage for supported values", + "nullable": true + }, + "preferredLanguage": { + "type": "string", + "description": "Preferred language for TTS and notifications (BCP-47, e.g. en-US, de-DE). Alias for voiceLanguage", + "nullable": true + } + }, + "required": [ + "channelType" + ] + }, + "UpdatePushbulletChannelConfig": { + "type": "object", + "properties": { + "channelType": { + "type": "string", + "enum": [ + "pushbullet" + ] + }, + "accessToken": { + "type": "string", + "description": "Pushbullet access token", + "nullable": true + }, + "deviceIden": { + "type": "string", + "description": "Target device identifier (broadcasts to all if empty)", + "nullable": true + } + }, + "required": [ + "channelType" + ] + }, + "UpdatePushoverChannelConfig": { + "type": "object", + "properties": { + "channelType": { + "type": "string", + "enum": [ + "pushover" + ] + }, + "userKey": { + "type": "string", + "description": "Pushover user or group key", + "nullable": true + }, + "appToken": { + "type": "string", + "description": "Pushover application API token", + "nullable": true + }, + "priority": { + "type": "string", + "description": "Notification priority override (-2 to 2)", + "nullable": true + }, + "sound": { + "type": "string", + "description": "Notification sound override", + "nullable": true + } + }, + "required": [ + "channelType" + ] + }, "UpdateResourceGroupRequest": { "required": [ "name" @@ -34451,6 +38655,30 @@ }, "description": "Request body for updating a resource group" }, + "UpdateRootlyChannelConfig": { + "type": "object", + "properties": { + "channelType": { + "type": "string", + "enum": [ + "rootly" + ] + }, + "apiKey": { + "type": "string", + "description": "Rootly API token with incident creation permission", + "nullable": true + }, + "severity": { + "type": "string", + "description": "Severity slug override (e.g. sev0, sev1)", + "nullable": true + } + }, + "required": [ + "channelType" + ] + }, "UpdateSecretRequest": { "required": [ "value" @@ -34465,6 +38693,95 @@ } } }, + "UpdateSlackChannelConfig": { + "type": "object", + "properties": { + "channelType": { + "type": "string", + "enum": [ + "slack" + ] + }, + "webhookUrl": { + "type": "string", + "description": "Slack incoming webhook URL", + "nullable": true + }, + "mentionText": { + "type": "string", + "description": "Optional mention text included in notifications, e.g. @channel", + "nullable": true + } + }, + "required": [ + "channelType" + ] + }, + "UpdateSmsChannelConfig": { + "type": "object", + "properties": { + "channelType": { + "type": "string", + "enum": [ + "sms" + ] + }, + "phoneNumber": { + "type": "string", + "description": "Recipient phone number in E.164 format; null preserves current", + "nullable": true + }, + "verifiedPhoneNumberId": { + "type": "integer", + "description": "Id of an org verified_phone_number row; null preserves current when phoneNumber also null", + "format": "int64", + "nullable": true + }, + "phoneNumbers": { + "type": "array", + "description": "Deprecated: use phoneNumber", + "nullable": true, + "items": { + "type": "string", + "description": "Deprecated: use phoneNumber", + "nullable": true + } + }, + "preferredLanguage": { + "type": "string", + "description": "Preferred language for SMS body (BCP-47, e.g. en-US, de-DE). Default: en-US", + "nullable": true + } + }, + "required": [ + "channelType" + ] + }, + "UpdateSplunkOnCallChannelConfig": { + "required": [ + "channelType", + "routingKey" + ], + "type": "object", + "properties": { + "channelType": { + "type": "string", + "enum": [ + "splunk_oncall" + ] + }, + "apiKey": { + "type": "string", + "description": "Splunk On-Call REST API key", + "nullable": true + }, + "routingKey": { + "minLength": 1, + "type": "string", + "description": "Routing key for alert routing" + } + } + }, "UpdateStatusPageComponentGroupRequest": { "type": "object", "properties": { @@ -34685,6 +39002,84 @@ }, "description": "Request body for updating a tag; null fields are left unchanged" }, + "UpdateTeamsChannelConfig": { + "type": "object", + "properties": { + "channelType": { + "type": "string", + "enum": [ + "teams" + ] + }, + "webhookUrl": { + "type": "string", + "description": "Microsoft Teams incoming webhook URL", + "nullable": true + } + }, + "required": [ + "channelType" + ] + }, + "UpdateTelegramChannelConfig": { + "required": [ + "channelType", + "chatId" + ], + "type": "object", + "properties": { + "channelType": { + "type": "string", + "enum": [ + "telegram" + ] + }, + "botToken": { + "type": "string", + "description": "Telegram bot token from @BotFather", + "nullable": true + }, + "chatId": { + "minLength": 1, + "type": "string", + "description": "Chat, group, or channel ID to send alerts to" + } + } + }, + "UpdateWebhookChannelConfig": { + "type": "object", + "properties": { + "channelType": { + "type": "string", + "enum": [ + "webhook" + ] + }, + "url": { + "type": "string", + "description": "Webhook endpoint URL that receives alert payloads", + "nullable": true + }, + "signingSecret": { + "type": "string", + "description": "HMAC secret for X-DevHelm-Signature header; omit for unsigned delivery", + "nullable": true + }, + "customHeaders": { + "type": "object", + "additionalProperties": { + "type": "string", + "description": "Additional HTTP headers to include in webhook requests", + "nullable": true + }, + "description": "Additional HTTP headers to include in webhook requests", + "nullable": true + } + }, + "required": [ + "channelType" + ] + }, "UpdateWebhookEndpointRequest": { "type": "object", "properties": { @@ -34745,6 +39140,25 @@ }, "description": "Update workspace details" }, + "UpdateZapierChannelConfig": { + "type": "object", + "properties": { + "channelType": { + "type": "string", + "enum": [ + "zapier" + ] + }, + "webhookUrl": { + "type": "string", + "description": "Zapier/n8n/Make catch webhook URL", + "nullable": true + } + }, + "required": [ + "channelType" + ] + }, "UptimeBucketDto": { "required": [ "timestamp", @@ -34809,14 +39223,48 @@ "format": "double", "nullable": true, "example": 312 + }, + "p50LatencyMs": { + "type": "number", + "description": "50th-percentile (median) latency in milliseconds; null when no data", + "format": "double", + "nullable": true, + "example": 128 + }, + "incidentCount": { + "type": "integer", + "description": "Number of incidents that started within the requested window", + "format": "int64", + "example": 2 } }, "description": "Uptime statistics aggregated from continuous aggregates", "required": [ "totalChecks", - "passedChecks" + "passedChecks", + "incidentCount" ] }, + "VoiceLanguageDto": { + "required": [ + "code", + "label" + ], + "type": "object", + "properties": { + "code": { + "minLength": 1, + "type": "string", + "description": "BCP-47 locale code, e.g. en-US" + }, + "label": { + "minLength": 1, + "type": "string", + "description": "Human-readable label, e.g. English (US)" + } + }, + "description": "Supported TTS voice language for phone call alerts" + }, "WebhookChannelConfig": { "required": [ "channelType", @@ -34837,7 +39285,7 @@ }, "signingSecret": { "type": "string", - "description": "Optional HMAC signing secret for payload verification", + "description": "HMAC secret for X-DevHelm-Signature header; omit for unsigned delivery", "nullable": true }, "customHeaders": { diff --git a/src/devhelm/_generated.py b/src/devhelm/_generated.py index 0b19ffa..4ce2ea9 100644 --- a/src/devhelm/_generated.py +++ b/src/devhelm/_generated.py @@ -86,14 +86,40 @@ class AddResourceGroupMemberRequest(BaseModel): ] +class Channel(StrEnum): + email = "EMAIL" + sms = "SMS" + webhook = "WEBHOOK" + + class AdminAddSubscriberRequest(BaseModel): model_config = ConfigDict(extra="forbid", populate_by_name=True) email: Annotated[ - EmailStr, + EmailStr | None, Field( - description="Email address to add as a confirmed subscriber", min_length=1 + description="Email for EMAIL channel; legacy clients may send only this", + max_length=320, + min_length=0, ), - ] + ] = None + channel: Annotated[ + Channel | None, Field(description="Delivery channel (default: EMAIL)") + ] = None + destination: Annotated[ + str | None, + Field( + description="Channel destination (email, phone, or webhook URL)", + max_length=2048, + min_length=0, + ), + ] = None + component_ids: Annotated[ + list[UUID] | None, + Field( + alias="componentIds", + description="Optional component IDs to scope; null means whole page", + ), + ] = None class Status(StrEnum): @@ -173,6 +199,41 @@ class AlertChannelDisplayConfig(BaseModel): project_key: Annotated[ str | None, Field(alias="projectKey", description="Jira project key") ] = None + phone_number: Annotated[ + str | None, + Field( + alias="phoneNumber", + description="Recipient phone number in E.164 format (SMS / phone-call channels)", + ), + ] = None + verified_phone_number_id: Annotated[ + int | None, + Field( + alias="verifiedPhoneNumberId", + description="Id of the org verified_phone_number row bound to this channel", + ), + ] = None + phone_numbers: Annotated[ + list[str] | None, + Field( + alias="phoneNumbers", + description="Deprecated mirror of phoneNumber as a length-1 list for older clients", + ), + ] = None + voice_language: Annotated[ + str | None, + Field( + alias="voiceLanguage", + description="BCP-47 voice language for phone-call TTS (e.g. en-US, de-DE)", + ), + ] = None + preferred_language: Annotated[ + str | None, + Field( + alias="preferredLanguage", + description="Preferred language for SMS/voice (BCP-47, e.g. en-US, de-DE)", + ), + ] = None class AlertChannelDto(BaseModel): @@ -189,6 +250,10 @@ class AlertChannelDto(BaseModel): display_config: Annotated[ AlertChannelDisplayConfig | None, Field(alias="displayConfig") ] = None + enabled: Annotated[ + bool, + Field(description="Whether this channel is enabled and will receive alerts"), + ] created_at: Annotated[ AwareDatetime, Field(alias="createdAt", description="Timestamp when the channel was created"), @@ -549,6 +614,21 @@ class ChartBucketDto(BaseModel): ] = None +class CodeCheckStep(BaseModel): + model_config = ConfigDict(extra="forbid", populate_by_name=True) + name: Annotated[str, Field(description="Step name from test.step() or test() call")] + status: Annotated[ + str, Field(description="Step outcome: passed, failed, skipped, or timedOut") + ] + duration_ms: Annotated[ + int | None, + Field(alias="durationMs", description="Step duration in milliseconds"), + ] = None + error: Annotated[ + str | None, Field(description="Error message if the step failed") + ] = None + + class ComponentImpact(BaseModel): model_config = ConfigDict(extra="forbid", populate_by_name=True) component_id: Annotated[ @@ -601,6 +681,23 @@ class ComponentPosition(BaseModel): ] = None +class ComponentSample(BaseModel): + model_config = ConfigDict(extra="forbid", populate_by_name=True) + component_id: Annotated[ + UUID, Field(alias="componentId", description="Component ID") + ] + component_name: Annotated[ + str | None, Field(alias="componentName", description="Component display name") + ] = None + old_status: Annotated[ + str | None, + Field(alias="oldStatus", description="Previous status before the flip"), + ] = None + new_status: Annotated[ + str, Field(alias="newStatus", description="New status after the flip") + ] + + class ComponentsSummaryDto(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) total_count: Annotated[ @@ -638,6 +735,30 @@ class ComponentStatusDto(BaseModel): ] +class ComponentTransitionEventDto(BaseModel): + model_config = ConfigDict(extra="ignore", populate_by_name=True) + new_status: Annotated[ + str, + Field( + alias="newStatus", description="New status that defines this rollup bucket" + ), + ] + component_count: Annotated[ + int, + Field( + alias="componentCount", + description="Total components in the 5-minute rollup bucket", + ), + ] + component_sample: Annotated[ + list[ComponentSample], + Field( + alias="componentSample", + description="Up to 5 sample components from the bucket", + ), + ] + + class ComponentUptimeSummaryDto(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) day: Annotated[ @@ -834,6 +955,20 @@ class CreateManualIncidentRequest(BaseModel): str | None, Field(description="Detailed description or context for the incident"), ] = None + service_id: Annotated[ + UUID | None, + Field( + alias="serviceId", + description="Vendor service to link; optional for Dependencies create CTA", + ), + ] = None + service_incident_id: Annotated[ + UUID | None, + Field( + alias="serviceIncidentId", + description="Vendor incident to link; idempotent if an active org incident already links it", + ), + ] = None class Type(StrEnum): @@ -843,6 +978,8 @@ class Type(StrEnum): tcp = "TCP" icmp = "ICMP" heartbeat = "HEARTBEAT" + browser = "BROWSER" + multi_step_api = "MULTI_STEP_API" class HealthThresholdType(StrEnum): @@ -1023,6 +1160,13 @@ class CreateStatusPageIncidentRequest(BaseModel): description="Whether to email confirmed subscribers about this incident (default: true)", ), ] = None + monitoring_incident_id: Annotated[ + UUID | None, + Field( + alias="monitoringIncidentId", + description="Monitoring incident ID to link this status page incident to; null for standalone", + ), + ] = None class CreateStatusPageIncidentUpdateRequest(BaseModel): @@ -1121,6 +1265,25 @@ class CreateWorkspaceRequest(BaseModel): name: Annotated[str, Field(description="Workspace name", min_length=1)] +class CreditTier(BaseModel): + model_config = ConfigDict(extra="forbid", populate_by_name=True) + uptime_range: Annotated[ + str, + Field(alias="uptimeRange", description="Uptime range, e.g. '99.1% – 99.98%'"), + ] + credit_percent: Annotated[ + int | None, + Field(alias="creditPercent", description="Credit percent of monthly fee"), + ] = None + formula: Annotated[ + str | None, + Field(description="Credit formula when percent is not a fixed number"), + ] = None + notes: Annotated[ + str | None, Field(description="Additional notes on this credit tier") + ] = None + + class DatadogChannelConfig(BaseModel): model_config = ConfigDict(extra="forbid", populate_by_name=True) channel_type: Annotated[Literal["datadog"], Field(alias="channelType")] = "datadog" @@ -2050,6 +2213,27 @@ class IcmpResponseTimeWarnAssertion(BaseModel): ] +class IncidentActivityEventDto(BaseModel): + model_config = ConfigDict(extra="ignore", populate_by_name=True) + id: Annotated[UUID, Field(description="Stable event ID (source row ID)")] + at: Annotated[ + AwareDatetime, Field(description="When the event occurred (ISO 8601)") + ] + kind: Annotated[ + str, + Field(description="Activity event kind in the merged incident activity stream"), + ] + actor: Annotated[ + str | None, + Field(description="Actor label when known (user email, system, etc.)"), + ] = None + summary: Annotated[str, Field(description="Human-readable summary of the event")] + payload: Annotated[ + dict[str, dict[str, Any]] | None, + Field(description="Kind-specific structured fields"), + ] = None + + class IncidentDto(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) id: Annotated[UUID, Field(description="Unique incident identifier")] @@ -2116,6 +2300,13 @@ class IncidentDto(BaseModel): description="Whether this incident is visible on the status page", ), ] + suppress_dispatch: Annotated[ + bool, + Field( + alias="suppressDispatch", + description="When true, alert channels are suppressed (AWARENESS silent tracking); false means Alerted", + ), + ] service_incident_id: Annotated[ UUID | None, Field( @@ -2154,6 +2345,13 @@ class IncidentDto(BaseModel): description="How the incident was resolved (AUTO_RECOVERED, MANUAL, etc.)", ), ] = None + resolution_note: Annotated[ + str | None, + Field( + alias="resolutionNote", + description="Body from the most recent resolve update; null when not currently resolved, auto-resolved without a note, or no resolve update body was provided", + ), + ] = None started_at: Annotated[ AwareDatetime | None, Field( @@ -2265,6 +2463,75 @@ class IncidentDto(BaseModel): description="Detection engine semver that evaluated the rule. Omitted from JSON when null, treat missing as null.", ), ] = None + display_key: Annotated[ + str | None, + Field( + alias="displayKey", + description='Org-scoped human-readable incident code, e.g. "ABC-42". Null on incidents created by pre-INC-keys API pods before the sweep; treat missing as unknown and fall back to the id', + ), + ] = None + + +class IncidentEventDto(BaseModel): + model_config = ConfigDict(extra="ignore", populate_by_name=True) + incident_id: Annotated[ + UUID, Field(alias="incidentId", description="Vendor catalog incident ID") + ] + external_id: Annotated[ + str | None, + Field(alias="externalId", description="Vendor-supplied external incident ID"), + ] = None + title: Annotated[ + str, Field(description="Incident title from the vendor status page") + ] + impact: Annotated[ + str | None, Field(description="Vendor impact level (major, minor, none)") + ] = None + status: Annotated[ + str | None, + Field(description="Vendor lifecycle status (only set on incident.update rows)"), + ] = None + body: Annotated[ + str | None, + Field(description="Update body text (only set on incident.update rows)"), + ] = None + shortlink: Annotated[ + str | None, Field(description="Short public URL for the vendor incident") + ] = None + started_at: Annotated[ + AwareDatetime | None, + Field(alias="startedAt", description="When the vendor incident started"), + ] = None + resolved_at: Annotated[ + AwareDatetime | None, + Field(alias="resolvedAt", description="When the vendor incident resolved"), + ] = None + detected_at: Annotated[ + AwareDatetime | None, + Field( + alias="detectedAt", description="When DevHelm first detected the incident" + ), + ] = None + vendor_created_at: Annotated[ + AwareDatetime | None, + Field( + alias="vendorCreatedAt", description="Vendor-reported creation timestamp" + ), + ] = None + duration_seconds: Annotated[ + int | None, + Field( + alias="durationSeconds", + description="Total duration in seconds (set on incident.resolved)", + ), + ] = None + affected_component_ids: Annotated[ + list[UUID] | None, + Field( + alias="affectedComponentIds", + description="Affected component IDs from the vendor incident join", + ), + ] = None class Status5(StrEnum): @@ -2335,6 +2602,13 @@ class IncidentFilterParams(BaseModel): description="Only return incidents whose monitor lives in this environment", ), ] = None + exclude_id: Annotated[ + UUID | None, + Field( + alias="excludeId", + description="Exclude this incident ID from results (related-incident lists)", + ), + ] = None started_from: Annotated[ AwareDatetime | None, Field( @@ -2415,6 +2689,57 @@ class IncidentsSummaryDto(BaseModel): mttr30d: float | None = None +class IncidentTriggerDto(BaseModel): + model_config = ConfigDict(extra="ignore", populate_by_name=True) + rule_type: Annotated[ + str | None, + Field( + alias="ruleType", + description="Trigger rule type (consecutive_failures, failures_in_window, response_time); null when unknown", + ), + ] = None + rule_index: Annotated[ + int | None, + Field( + alias="ruleIndex", + description="0-based index into the policy trigger_rules array; null when unknown", + ), + ] = None + count: Annotated[ + int | None, + Field( + description="Observed failing_streak or failures_in_window from forensics; null when unavailable" + ), + ] = None + threshold: Annotated[ + int | None, + Field( + description="Rule required count or threshold_ms from forensics; null when unavailable" + ), + ] = None + last_error: Annotated[ + str | None, + Field( + alias="lastError", + description="failure_reason from the triggering check result; null when unavailable", + ), + ] = None + first_failed_check_at: Annotated[ + AwareDatetime | None, + Field( + alias="firstFailedCheckAt", + description="Earliest failing check timestamp in the confirm window when computable; null otherwise", + ), + ] = None + source: Annotated[ + str, + Field( + description="Where the enrichment came from: forensics, checks, or none (STATUS_DATA/manual/no data)", + min_length=1, + ), + ] + + class IncidentUpdateDto(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) id: UUID @@ -2453,6 +2778,10 @@ class InviteDto(BaseModel): description="Role that will be assigned to the invitee on acceptance", ), ] + created_at: Annotated[ + AwareDatetime, + Field(alias="createdAt", description="Timestamp when the invite was created"), + ] expires_at: Annotated[ AwareDatetime, Field(alias="expiresAt", description="Timestamp when the invite expires"), @@ -2564,15 +2893,58 @@ class LinearChannelConfig(BaseModel): class LinkedStatusPageIncidentDto(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - id: UUID - status_page_id: Annotated[UUID, Field(alias="statusPageId")] - status_page_name: Annotated[str, Field(alias="statusPageName")] - status_page_slug: Annotated[str, Field(alias="statusPageSlug")] - title: str - status: str - impact: str - scheduled: bool - published_at: Annotated[AwareDatetime | None, Field(alias="publishedAt")] = None + id: Annotated[ + UUID, + Field( + description="Status page incident ID (same value as spIncidentId; kept for backwards compatibility)" + ), + ] + sp_incident_id: Annotated[ + UUID, + Field( + alias="spIncidentId", + description="Status page incident ID (alias for id) — use this when the outer context is a monitoring incident", + ), + ] + status_page_id: Annotated[ + UUID, Field(alias="statusPageId", description="Parent status page ID") + ] + status_page_name: Annotated[ + str, + Field(alias="statusPageName", description="Parent status page display name"), + ] + status_page_slug: Annotated[ + str, Field(alias="statusPageSlug", description="Parent status page URL slug") + ] + title: Annotated[str, Field(description="Customer-facing incident title")] + status: Annotated[ + str, + Field( + description="Current lifecycle status (INVESTIGATING, IDENTIFIED, MONITORING, RESOLVED)" + ), + ] + impact: Annotated[ + str, Field(description="Impact level (NONE, MINOR, MAJOR, CRITICAL)") + ] + scheduled: Annotated[bool, Field(description="Scheduled maintenance flag")] + published_at: Annotated[ + AwareDatetime | None, + Field(alias="publishedAt", description="Publish time; null while draft"), + ] = None + connection_mode: Annotated[ + str, + Field( + alias="connectionMode", + description="Whether the linked SPI was created by automation (AUTO) or by a human/API caller (MANUAL)", + ), + ] + page_incident_mode: Annotated[ + str, + Field( + alias="pageIncidentMode", + description="Incident mode of the parent status page at read time (MANUAL, REVIEW, AUTOMATIC)", + ), + ] class MaintenanceComponentRef(BaseModel): @@ -2584,12 +2956,60 @@ class MaintenanceComponentRef(BaseModel): ] -class MaintenanceUpdateDto(BaseModel): +class MaintenanceEventDto(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - id: Annotated[UUID, Field(description="Unique update identifier")] - status: Annotated[str, Field(description="Status at the time of this update")] - body: Annotated[str | None, Field(description="Update message from the vendor")] = ( - None + maintenance_id: Annotated[ + UUID, Field(alias="maintenanceId", description="Vendor catalog maintenance ID") + ] + external_id: Annotated[ + str, + Field( + alias="externalId", description="Vendor-supplied external maintenance ID" + ), + ] + title: Annotated[ + str, Field(description="Maintenance title from the vendor status page") + ] + status: Annotated[ + str, + Field( + description="Lifecycle status: scheduled, in_progress, verifying, completed" + ), + ] + impact: Annotated[str | None, Field(description="Vendor impact level")] = None + shortlink: Annotated[ + str | None, Field(description="Short public URL for the vendor maintenance") + ] = None + scheduled_for: Annotated[ + AwareDatetime | None, + Field( + alias="scheduledFor", + description="Scheduled start; null for undated maintenance", + ), + ] = None + scheduled_until: Annotated[ + AwareDatetime | None, Field(alias="scheduledUntil", description="Scheduled end") + ] = None + started_at: Annotated[ + AwareDatetime | None, + Field(alias="startedAt", description="When maintenance actually started"), + ] = None + completed_at: Annotated[ + AwareDatetime | None, + Field(alias="completedAt", description="When maintenance completed"), + ] = None + affected_component_ids: Annotated[ + list[UUID] | None, + Field(alias="affectedComponentIds", description="Affected component IDs"), + ] = None + + +class MaintenanceUpdateDto(BaseModel): + model_config = ConfigDict(extra="ignore", populate_by_name=True) + id: Annotated[UUID, Field(description="Unique update identifier")] + status: Annotated[str, Field(description="Status at the time of this update")] + body: Annotated[str | None, Field(description="Update message from the vendor")] = ( + None ) display_at: Annotated[ AwareDatetime | None, @@ -2946,6 +3366,8 @@ class Type3(StrEnum): tcp = "TCP" icmp = "ICMP" heartbeat = "HEARTBEAT" + browser = "BROWSER" + multi_step_api = "MULTI_STEP_API" class MonitorTestResultDto(BaseModel): @@ -2979,6 +3401,33 @@ class NewTagRequest(BaseModel): ] = None +class NoSlaContext(BaseModel): + model_config = ConfigDict(extra="forbid", populate_by_name=True) + reason: Annotated[str | None, Field(description="Reason no SLA is published")] = ( + None + ) + historical_claim: Annotated[ + str | None, + Field( + alias="historicalClaim", description="Non-binding historical uptime claim" + ), + ] = None + support_sla: Annotated[ + str | None, + Field( + alias="supportSla", + description="Support response time SLA if different from uptime SLA", + ), + ] = None + enterprise_note: Annotated[ + str | None, + Field( + alias="enterpriseNote", + description="Note about enterprise/custom SLA availability", + ), + ] = None + + class NotificationDispatchDto(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) id: Annotated[UUID, Field(description="Unique dispatch record identifier")] @@ -3028,6 +3477,27 @@ class NotificationDispatchDto(BaseModel): description="Timestamp when this dispatch was acknowledged (null if not acknowledged)", ), ] = None + acknowledged_by: Annotated[ + str | None, + Field( + alias="acknowledgedBy", + description="Actor who acknowledged this dispatch (user email, api-key:, voice:, etc.); null if not acknowledged", + ), + ] = None + acknowledged_via: Annotated[ + str | None, + Field( + alias="acknowledgedVia", + description="Channel used to acknowledge (DASHBOARD, API, PHONE_CALL, INTERNAL, etc.); null if not acknowledged", + ), + ] = None + matched_rules: Annotated[ + list[str] | None, + Field( + alias="matchedRules", + description='Labels of match rules that caused this dispatch (same wording as TestMatchResult); null on pre-V138 rows; catch-all is ["(catch-all: no rules defined)"]', + ), + ] = None next_escalation_at: Annotated[ AwareDatetime | None, Field( @@ -3095,6 +3565,36 @@ class NotificationDto(BaseModel): ] +class OfficialSla(BaseModel): + model_config = ConfigDict(extra="forbid", populate_by_name=True) + percentage: Annotated[ + str | None, Field(description="Advertised uptime percentage, e.g. '99.99%'") + ] = None + scope: Annotated[ + str | None, + Field(description="Scope of the SLA, e.g. 'Monthly uptime per region'"), + ] = None + measurement: Annotated[ + str | None, Field(description="How the vendor measures uptime for SLA purposes") + ] = None + exclusions: Annotated[ + str | None, Field(description="Summary of exclusions from SLA calculation") + ] = None + applies_to_plans: Annotated[ + list[str] | None, + Field( + alias="appliesToPlans", + description="Plan names this SLA applies to, e.g. ['Enterprise']", + ), + ] = None + not_covered: Annotated[ + str | None, + Field( + alias="notCovered", description="Services/components NOT covered by the SLA" + ), + ] = None + + class OpsGenieChannelConfig(BaseModel): model_config = ConfigDict(extra="forbid", populate_by_name=True) channel_type: Annotated[Literal["opsgenie"], Field(alias="channelType")] = ( @@ -3129,6 +3629,32 @@ class OrganizationDto(BaseModel): ] = None +class OrgIncidentAnnotationDto(BaseModel): + model_config = ConfigDict(extra="ignore", populate_by_name=True) + incident_id: Annotated[ + UUID, Field(alias="incidentId", description="Internal org incident ID") + ] + display_key: Annotated[ + str | None, + Field( + alias="displayKey", + description="Human display key (e.g. DEV-42); null until platform INC codes ship", + ), + ] = None + status: Annotated[str, Field(description="Internal incident lifecycle status")] + severity: Annotated[str, Field(description="Internal incident severity")] + alerted: Annotated[ + bool, + Field( + description="Whether alert channels were eligible to fire (false for AWARENESS silent tracking)" + ), + ] + started_at: Annotated[ + AwareDatetime | None, + Field(alias="startedAt", description="When the internal incident started"), + ] = None + + class OrgInfo(BaseModel): model_config = ConfigDict(extra="forbid", populate_by_name=True) id: Annotated[int, Field(description="Organization ID")] @@ -3181,6 +3707,48 @@ class PageSection(BaseModel): ] +class PhoneCallChannelConfig(BaseModel): + model_config = ConfigDict(extra="forbid", populate_by_name=True) + channel_type: Annotated[Literal["phone_call"], Field(alias="channelType")] = ( + "phone_call" + ) + phone_number: Annotated[ + str | None, + Field( + alias="phoneNumber", + description="Recipient phone number in E.164 format, e.g. +14155550123", + ), + ] = None + verified_phone_number_id: Annotated[ + int | None, + Field( + alias="verifiedPhoneNumberId", + description="Id of an org verified_phone_number row; alternative to phoneNumber", + ), + ] = None + phone_numbers: Annotated[ + list[str] | None, + Field( + alias="phoneNumbers", + description="Deprecated: use phoneNumber. Accepted as a length-1 list for one release; ignored when phoneNumber or id is set", + ), + ] = None + voice_language: Annotated[ + str | None, + Field( + alias="voiceLanguage", + description="TTS voice language/locale (default: en-US). See VoiceLanguage for supported values", + ), + ] = None + preferred_language: Annotated[ + str | None, + Field( + alias="preferredLanguage", + description="Preferred language for TTS and notifications (BCP-47, e.g. en-US, de-DE). Alias for voiceLanguage", + ), + ] = None + + class Tier(StrEnum): free = "FREE" starter = "STARTER" @@ -3286,6 +3854,27 @@ class PollChartBucketDto(BaseModel): ] +class PricingTier(BaseModel): + model_config = ConfigDict(extra="forbid", populate_by_name=True) + name: Annotated[ + str, Field(description="Tier name, e.g. 'Free', 'Pro', 'Enterprise'") + ] + sla_percentage: Annotated[ + str | None, + Field( + alias="slaPercentage", + description="SLA percentage for this tier, e.g. '99.9%'", + ), + ] = None + price_from: Annotated[ + str | None, + Field( + alias="priceFrom", + description="Starting price, e.g. '$0', '$25/mo', 'Custom'", + ), + ] = None + + class Status6(StrEnum): investigating = "INVESTIGATING" identified = "IDENTIFIED" @@ -3481,6 +4070,20 @@ class RegionStatusDto(BaseModel): ] = None +class RelatedIncidentsResponse(BaseModel): + model_config = ConfigDict(extra="ignore", populate_by_name=True) + data: Annotated[ + list[IncidentDto], + Field(description="Related incident rows (newest first, capped by limit)"), + ] + total: Annotated[ + int, + Field( + description="Total matching incidents in the window, excluding the current incident" + ), + ] + + class RemoveMonitorTagsRequest(BaseModel): model_config = ConfigDict(extra="forbid", populate_by_name=True) tag_ids: Annotated[ @@ -3930,6 +4533,27 @@ class ScheduledMaintenanceDto(BaseModel): ] +class ScriptMonitorConfig(BaseModel): + model_config = ConfigDict(extra="forbid", populate_by_name=True) + script: Annotated[ + str, + Field( + description="Playwright test script source code", + max_length=65536, + min_length=1, + ), + ] + timeout_seconds: Annotated[ + int | None, + Field( + alias="timeoutSeconds", + description="Maximum execution time in seconds (5–120)", + ge=5, + le=120, + ), + ] = None + + class SecretDto(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) id: Annotated[UUID, Field(description="Unique secret identifier")] @@ -3986,6 +4610,21 @@ class SeoMetadataDto(BaseModel): ] = None +class ServiceBreakdown(BaseModel): + model_config = ConfigDict(extra="forbid", populate_by_name=True) + service: Annotated[str, Field(description="Sub-service name, e.g. 'EC2', 'S3'")] + sla_percentage: Annotated[ + str | None, + Field(alias="slaPercentage", description="SLA percentage for this sub-service"), + ] = None + scope: Annotated[ + str | None, Field(description="Scope qualifier, e.g. 'Region (Multi-AZ)'") + ] = None + notes: Annotated[ + str | None, Field(description="Additional notes on measurement or conditions") + ] = None + + class ServiceCatalogDto(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) id: UUID @@ -4006,6 +4645,13 @@ class ServiceCatalogDto(BaseModel): ] enabled: bool published: bool + sla_published: Annotated[ + bool, + Field( + alias="slaPublished", + description="Whether the service's SLA page is publicly visible", + ), + ] overall_status: Annotated[str | None, Field(alias="overallStatus")] = None created_at: Annotated[AwareDatetime, Field(alias="createdAt")] updated_at: Annotated[AwareDatetime, Field(alias="updatedAt")] @@ -4147,6 +4793,7 @@ class ServiceIncidentDto(BaseModel): vendor_created_at: Annotated[ AwareDatetime | None, Field(alias="vendorCreatedAt") ] = None + affected_regions: Annotated[list[str] | None, Field(alias="affectedRegions")] = None class ServiceIncidentUpdateDto(BaseModel): @@ -4388,11 +5035,51 @@ class SetAlertChannelsRequest(BaseModel): ] +class SetEnabledRequest(BaseModel): + model_config = ConfigDict(extra="forbid", populate_by_name=True) + enabled: Annotated[ + bool, Field(description="Whether the resource should be enabled") + ] + + class SetMonitorAuthRequest(BaseModel): model_config = ConfigDict(extra="forbid", populate_by_name=True) config: ApiKeyAuthConfig | BasicAuthConfig | BearerAuthConfig | HeaderAuthConfig +class Status7(StrEnum): + operational = "OPERATIONAL" + degraded_performance = "DEGRADED_PERFORMANCE" + partial_outage = "PARTIAL_OUTAGE" + major_outage = "MAJOR_OUTAGE" + under_maintenance = "UNDER_MAINTENANCE" + + +class SetStatusPageComponentOverrideRequest(BaseModel): + model_config = ConfigDict(extra="forbid", populate_by_name=True) + status: Annotated[ + Status7, + Field( + description="Override status while active; takes precedence over binding until expiry/clear" + ), + ] + reason: Annotated[ + str | None, + Field( + description="Optional operator reason shown in the builder", + max_length=2000, + min_length=0, + ), + ] = None + expires_at: Annotated[ + AwareDatetime, + Field( + alias="expiresAt", + description="When the override expires (must be in the future, at most 24h from now)", + ), + ] + + class SingleValueResponseAlertChannelDto(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) data: AlertChannelDto @@ -4518,6 +5205,24 @@ class SingleValueResponseString(BaseModel): data: str +class Status8(StrEnum): + pending = "PENDING" + dispatching = "DISPATCHING" + delivered = "DELIVERED" + escalating = "ESCALATING" + acknowledged = "ACKNOWLEDGED" + completed = "COMPLETED" + + +class SkippedDispatch(BaseModel): + model_config = ConfigDict(extra="forbid", populate_by_name=True) + id: Annotated[UUID, Field(description="Dispatch identifier")] + status: Annotated[Status8, Field(description="Current dispatch status")] + reason: Annotated[ + str, Field(description="Why this dispatch was skipped", min_length=1) + ] + + class SlackChannelConfig(BaseModel): model_config = ConfigDict(extra="forbid", populate_by_name=True) channel_type: Annotated[Literal["slack"], Field(alias="channelType")] = "slack" @@ -4536,6 +5241,63 @@ class SlackChannelConfig(BaseModel): ] = None +class SmsChannelConfig(BaseModel): + model_config = ConfigDict(extra="forbid", populate_by_name=True) + channel_type: Annotated[Literal["sms"], Field(alias="channelType")] = "sms" + phone_number: Annotated[ + str | None, + Field( + alias="phoneNumber", + description="Recipient phone number in E.164 format, e.g. +14155550123", + ), + ] = None + verified_phone_number_id: Annotated[ + int | None, + Field( + alias="verifiedPhoneNumberId", + description="Id of an org verified_phone_number row; alternative to phoneNumber", + ), + ] = None + phone_numbers: Annotated[ + list[str] | None, + Field( + alias="phoneNumbers", + description="Deprecated: use phoneNumber. Accepted as a length-1 list for one release; ignored when phoneNumber or id is set", + ), + ] = None + preferred_language: Annotated[ + str | None, + Field( + alias="preferredLanguage", + description="Preferred language for SMS body (BCP-47, e.g. en-US, de-DE). Default: en-US", + ), + ] = None + + +class SourceUrls(BaseModel): + model_config = ConfigDict(extra="forbid", populate_by_name=True) + sla_page: Annotated[ + str | None, Field(alias="slaPage", description="URL to vendor's SLA page") + ] = None + pricing_page: Annotated[ + str | None, + Field(alias="pricingPage", description="URL to vendor's pricing page"), + ] = None + tos_page: Annotated[ + str | None, + Field(alias="tosPage", description="URL to vendor's Terms of Service"), + ] = None + status_page: Annotated[ + str | None, Field(alias="statusPage", description="URL to vendor's status page") + ] = None + all_slas_page: Annotated[ + str | None, + Field( + alias="allSlasPage", description="URL to vendor's all-services SLA listing" + ), + ] = None + + class SplunkOnCallChannelConfig(BaseModel): model_config = ConfigDict(extra="forbid", populate_by_name=True) channel_type: Annotated[Literal["splunk_oncall"], Field(alias="channelType")] = ( @@ -4600,18 +5362,43 @@ class StatusCodeAssertion(BaseModel): ] -class StatusPageBranding(BaseModel): - model_config = ConfigDict(extra="forbid", populate_by_name=True) - logo_url: Annotated[ - str | None, +class StatusEventDto(BaseModel): + model_config = ConfigDict(extra="ignore", populate_by_name=True) + id: Annotated[ + UUID, Field( - alias="logoUrl", - description="URL for the logo image displayed in the header", - max_length=2048, - min_length=0, - pattern="^https?://.*", + description="Stable row ID (incident/update/maintenance UUID or transition bucket key)" ), - ] = None + ] + type: Annotated[ + str, Field(description="Status event row type on the Dependencies Detail rail") + ] + at: Annotated[ + AwareDatetime, + Field( + description="Canonical timestamp used for reverse-chronological ordering" + ), + ] + incident: IncidentEventDto | None = None + maintenance: MaintenanceEventDto | None = None + component: ComponentTransitionEventDto | None = None + org_annotation: Annotated[ + OrgIncidentAnnotationDto | None, Field(alias="orgAnnotation") + ] = None + + +class StatusPageBranding(BaseModel): + model_config = ConfigDict(extra="forbid", populate_by_name=True) + logo_url: Annotated[ + str | None, + Field( + alias="logoUrl", + description="URL for the logo image displayed in the header", + max_length=2048, + min_length=0, + pattern="^https?://.*", + ), + ] = None favicon_url: Annotated[ str | None, Field( @@ -4743,7 +5530,41 @@ class StatusPageComponentDto(BaseModel): type: str monitor_id: Annotated[UUID | None, Field(alias="monitorId")] = None resource_group_id: Annotated[UUID | None, Field(alias="resourceGroupId")] = None - current_status: Annotated[str, Field(alias="currentStatus")] + current_status: Annotated[ + str, + Field( + alias="currentStatus", + description="Effective display status (incident > active override > binding)", + ), + ] + override_status: Annotated[ + str | None, + Field( + alias="overrideStatus", + description="Active timed override status; null when unset or expired", + ), + ] = None + override_reason: Annotated[ + str | None, + Field( + alias="overrideReason", + description="Optional operator reason for the active override", + ), + ] = None + override_expires_at: Annotated[ + AwareDatetime | None, + Field( + alias="overrideExpiresAt", + description="When the active override expires; null when unset or expired", + ), + ] = None + override_actor: Annotated[ + int | None, + Field( + alias="overrideActor", + description="User id who set the override; null for API-key actors or when inactive", + ), + ] = None show_uptime: Annotated[bool, Field(alias="showUptime")] display_order: Annotated[int, Field(alias="displayOrder")] page_order: Annotated[int, Field(alias="pageOrder")] @@ -4831,12 +5652,135 @@ class StatusPageIncidentUpdateDto(BaseModel): created_at: Annotated[AwareDatetime, Field(alias="createdAt")] +class StatusPageMeasuredUptimeDayDto(BaseModel): + model_config = ConfigDict(extra="ignore", populate_by_name=True) + date: Annotated[ + AwareDatetime, + Field( + description="Start-of-day timestamp for this bucket (UTC midnight, ISO 8601)" + ), + ] + total_checks: Annotated[ + int, + Field( + alias="totalChecks", + description="Total probe checks recorded that day across regions", + ), + ] + passed_checks: Annotated[ + int, + Field( + alias="passedChecks", + description="Checks that passed that day across regions", + ), + ] + uptime_percentage: Annotated[ + float | None, + Field( + alias="uptimePercentage", + description="passedChecks / totalChecks × 100; null when totalChecks is 0", + ), + ] = None + + +class StatusPageNotificationDeliveryDto(BaseModel): + model_config = ConfigDict(extra="ignore", populate_by_name=True) + id: Annotated[UUID, Field(description="Delivery receipt ID")] + status_page_id: Annotated[ + UUID, + Field(alias="statusPageId", description="Status page that owns this delivery"), + ] + subscriber_id: Annotated[ + UUID, + Field(alias="subscriberId", description="Subscriber this delivery targeted"), + ] + destination: Annotated[ + str | None, + Field(description="Subscriber destination (email, phone, or webhook URL)"), + ] = None + channel: Annotated[ + str, + Field(description="Delivery channel from the subscriber (EMAIL, SMS, WEBHOOK)"), + ] + incident_id: Annotated[ + UUID | None, + Field( + alias="incidentId", description="Related status-page incident ID, if any" + ), + ] = None + incident_update_id: Annotated[ + UUID | None, + Field( + alias="incidentUpdateId", description="Related incident update ID, if any" + ), + ] = None + event_type: Annotated[ + str, + Field( + alias="eventType", + description="Notification event type that triggered this delivery", + ), + ] + status: Annotated[str, Field(description="Current delivery status")] + attempt_count: Annotated[ + int, Field(alias="attemptCount", description="Number of delivery attempts made") + ] + last_attempt_at: Annotated[ + AwareDatetime | None, + Field(alias="lastAttemptAt", description="When the last attempt was made"), + ] = None + next_retry_at: Annotated[ + AwareDatetime | None, + Field( + alias="nextRetryAt", + description="When the next retry is scheduled; null if not retrying", + ), + ] = None + delivered_at: Annotated[ + AwareDatetime | None, + Field( + alias="deliveredAt", + description="When delivery was confirmed; null if not delivered", + ), + ] = None + error_message: Annotated[ + str | None, + Field( + alias="errorMessage", + description="Error summary from the last failed attempt", + ), + ] = None + created_at: Annotated[ + AwareDatetime, + Field(alias="createdAt", description="When the delivery row was created"), + ] + + class StatusPageSubscriberDto(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) - id: UUID - email: str - confirmed: bool - created_at: Annotated[AwareDatetime, Field(alias="createdAt")] + id: Annotated[UUID, Field(description="Subscriber id")] + email: Annotated[ + str | None, + Field(description="Email when channel is EMAIL; null for other channels"), + ] = None + channel: Annotated[str, Field(description="Delivery channel (EMAIL, SMS, WEBHOOK)")] + destination: Annotated[ + str, Field(description="Channel destination (email, phone, or webhook URL)") + ] + component_ids: Annotated[ + list[UUID] | None, + Field( + alias="componentIds", + description="Scoped component IDs; null means whole page", + ), + ] = None + confirmed: Annotated[ + bool, Field(description="Whether the subscriber has confirmed opt-in") + ] + created_at: Annotated[ + AwareDatetime, + Field(alias="createdAt", description="When the subscriber was created"), + ] class Summary(BaseModel): @@ -5044,6 +5988,15 @@ class TableValueResultStatusPageDto(BaseModel): total_pages: Annotated[int | None, Field(alias="totalPages")] = None +class TableValueResultStatusPageNotificationDeliveryDto(BaseModel): + model_config = ConfigDict(extra="ignore", populate_by_name=True) + data: list[StatusPageNotificationDeliveryDto] + has_next: Annotated[bool, Field(alias="hasNext")] + has_prev: Annotated[bool, Field(alias="hasPrev")] + total_elements: Annotated[int | None, Field(alias="totalElements")] = None + total_pages: Annotated[int | None, Field(alias="totalPages")] = None + + class TableValueResultStatusPageSubscriberDto(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) data: list[StatusPageSubscriberDto] @@ -5188,6 +6141,24 @@ class TestMatchResult(BaseModel): ] +class TestMonitorNotificationsRequest(BaseModel): + model_config = ConfigDict(extra="forbid", populate_by_name=True) + channel_ids: Annotated[ + list[UUID] | None, + Field( + alias="channelIds", + description="Channel IDs to test; null or empty tests all channels attached to the monitor", + ), + ] = None + include_resolved: Annotated[ + bool, + Field( + alias="includeResolved", + description="Whether to include a resolved notification in the test (default: false)", + ), + ] + + class TestNotificationPolicyRequest(BaseModel): model_config = ConfigDict(extra="forbid", populate_by_name=True) severity: Annotated[ @@ -5261,7 +6232,10 @@ class TimingPhasesDto(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) dns_ms: Annotated[ int | None, - Field(description="DNS resolution time in milliseconds", examples=[12]), + Field( + description="Legacy DNS phase; null for new checks (no longer measured)", + examples=[12], + ), ] = None tcp_ms: Annotated[ int | None, Field(description="TCP connect time in milliseconds", examples=[18]) @@ -5489,6 +6463,47 @@ class UpdateAssertionRequest(BaseModel): ] = None +class UpdateDatadogChannelConfig(BaseModel): + model_config = ConfigDict(extra="forbid", populate_by_name=True) + channel_type: Annotated[Literal["datadog"], Field(alias="channelType")] = "datadog" + api_key: Annotated[ + str | None, Field(alias="apiKey", description="Datadog API key") + ] = None + site: Annotated[ + str | None, + Field( + description="Datadog site region (e.g. datadoghq.com, datadoghq.eu, us3.datadoghq.com)" + ), + ] = None + tags: Annotated[ + str | None, Field(description="Comma-separated tags to attach to events") + ] = None + + +class UpdateDiscordChannelConfig(BaseModel): + model_config = ConfigDict(extra="forbid", populate_by_name=True) + channel_type: Annotated[Literal["discord"], Field(alias="channelType")] = "discord" + webhook_url: Annotated[ + str | None, Field(alias="webhookUrl", description="Discord webhook URL") + ] = None + mention_role_id: Annotated[ + str | None, + Field( + alias="mentionRoleId", + description="Optional Discord role ID to mention in notifications", + ), + ] = None + + +class UpdateEmailChannelConfig(BaseModel): + model_config = ConfigDict(extra="forbid", populate_by_name=True) + channel_type: Annotated[Literal["email"], Field(alias="channelType")] = "email" + recipients: Annotated[ + list[EmailStr], + Field(description="Email addresses to send notifications to", min_length=1), + ] + + class UpdateEnvironmentRequest(BaseModel): model_config = ConfigDict(extra="forbid", populate_by_name=True) name: Annotated[ @@ -5512,50 +6527,181 @@ class UpdateEnvironmentRequest(BaseModel): ] = None -class UpdateIncidentPolicyRequest(BaseModel): +class UpdateGitLabChannelConfig(BaseModel): model_config = ConfigDict(extra="forbid", populate_by_name=True) - trigger_rules: Annotated[ - list[TriggerRule], + channel_type: Annotated[Literal["gitlab"], Field(alias="channelType")] = "gitlab" + endpoint_url: Annotated[ + str, Field( - alias="triggerRules", - description="Array of trigger rules; at least one required", + alias="endpointUrl", + description="GitLab alert integration endpoint URL", min_length=1, ), ] - confirmation: ConfirmationPolicy - recovery: RecoveryPolicy + authorization_key: Annotated[ + str | None, + Field( + alias="authorizationKey", + description="Authorization key from GitLab alert integration settings", + ), + ] = None -class UpdateMaintenanceWindowRequest(BaseModel): +class UpdateGoogleChatChannelConfig(BaseModel): model_config = ConfigDict(extra="forbid", populate_by_name=True) - monitor_id: Annotated[ - UUID | None, - Field( - alias="monitorId", - description="Monitor this window applies to; null switches the window to org-wide", - ), + channel_type: Annotated[Literal["google_chat"], Field(alias="channelType")] = ( + "google_chat" + ) + webhook_url: Annotated[ + str | None, + Field(alias="webhookUrl", description="Google Chat space webhook URL"), ] = None - starts_at: Annotated[ - AwareDatetime, - Field(alias="startsAt", description="Updated start time (ISO 8601)"), - ] - ends_at: Annotated[ - AwareDatetime, Field(alias="endsAt", description="Updated end time (ISO 8601)") - ] - repeat_rule: Annotated[ + + +class UpdateIncidentIoChannelConfig(BaseModel): + model_config = ConfigDict(extra="forbid", populate_by_name=True) + channel_type: Annotated[Literal["incident_io"], Field(alias="channelType")] = ( + "incident_io" + ) + api_key: Annotated[ str | None, Field( - alias="repeatRule", - description="Reserved: iCal RRULE for recurring windows (stored but not yet honored); null clears it", - max_length=100, - min_length=0, + alias="apiKey", + description="incident.io API key with 'Create incidents' permission", ), ] = None - reason: Annotated[ + severity_id: Annotated[ str | None, Field( - description="Updated reason (max 500 chars); null clears the existing reason", - max_length=500, + alias="severityId", + description="Severity ID for created incidents (from List Severities API)", + ), + ] = None + visibility: Annotated[ + str | None, + Field(description="Incident visibility: public or private (default: public)"), + ] = None + + +class UpdateIncidentPolicyRequest(BaseModel): + model_config = ConfigDict(extra="forbid", populate_by_name=True) + trigger_rules: Annotated[ + list[TriggerRule], + Field( + alias="triggerRules", + description="Array of trigger rules; at least one required", + min_length=1, + ), + ] + confirmation: ConfirmationPolicy + recovery: RecoveryPolicy + + +class Severity5(StrEnum): + down = "DOWN" + degraded = "DEGRADED" + maintenance = "MAINTENANCE" + + +class UpdateIncidentRequest(BaseModel): + model_config = ConfigDict(extra="forbid", populate_by_name=True) + title: Annotated[ + str | None, + Field( + description="New title; null preserves current (min 1 char if present)", + max_length=2147483647, + min_length=1, + ), + ] = None + severity: Annotated[ + Severity5 | None, + Field( + description="New severity: DOWN, DEGRADED, or MAINTENANCE; null preserves current" + ), + ] = None + + +class UpdateJiraChannelConfig(BaseModel): + model_config = ConfigDict(extra="forbid", populate_by_name=True) + channel_type: Annotated[Literal["jira"], Field(alias="channelType")] = "jira" + domain: Annotated[ + str, + Field( + description="Atlassian instance domain (e.g. yourteam.atlassian.net)", + min_length=1, + ), + ] + email: Annotated[ + str, + Field( + description="Atlassian account email for API authentication", min_length=1 + ), + ] + api_token: Annotated[ + str | None, Field(alias="apiToken", description="Atlassian API token") + ] = None + project_key: Annotated[ + str, + Field( + alias="projectKey", + description="Jira project key where issues are created (e.g. OPS)", + min_length=1, + ), + ] + issue_type: Annotated[ + str | None, + Field( + alias="issueType", description="Issue type name (e.g. Bug, Task, Incident)" + ), + ] = None + + +class UpdateLinearChannelConfig(BaseModel): + model_config = ConfigDict(extra="forbid", populate_by_name=True) + channel_type: Annotated[Literal["linear"], Field(alias="channelType")] = "linear" + api_key: Annotated[ + str | None, Field(alias="apiKey", description="Linear API key") + ] = None + team_id: Annotated[ + str, + Field(alias="teamId", description="Team ID to create issues in", min_length=1), + ] + label_id: Annotated[ + str | None, + Field(alias="labelId", description="Label ID to attach to created issues"), + ] = None + + +class UpdateMaintenanceWindowRequest(BaseModel): + model_config = ConfigDict(extra="forbid", populate_by_name=True) + monitor_id: Annotated[ + UUID | None, + Field( + alias="monitorId", + description="Monitor this window applies to; null switches the window to org-wide", + ), + ] = None + starts_at: Annotated[ + AwareDatetime, + Field(alias="startsAt", description="Updated start time (ISO 8601)"), + ] + ends_at: Annotated[ + AwareDatetime, Field(alias="endsAt", description="Updated end time (ISO 8601)") + ] + repeat_rule: Annotated[ + str | None, + Field( + alias="repeatRule", + description="Reserved: iCal RRULE for recurring windows (stored but not yet honored); null clears it", + max_length=100, + min_length=0, + ), + ] = None + reason: Annotated[ + str | None, + Field( + description="Updated reason (max 500 chars); null clears the existing reason", + max_length=500, min_length=0, ), ] = None @@ -5568,11 +6714,42 @@ class UpdateMaintenanceWindowRequest(BaseModel): ] = None +class UpdateMattermostChannelConfig(BaseModel): + model_config = ConfigDict(extra="forbid", populate_by_name=True) + channel_type: Annotated[Literal["mattermost"], Field(alias="channelType")] = ( + "mattermost" + ) + webhook_url: Annotated[ + str | None, + Field(alias="webhookUrl", description="Mattermost incoming webhook URL"), + ] = None + channel: Annotated[ + str | None, Field(description="Override channel (if webhook allows)") + ] = None + icon_url: Annotated[ + str | None, Field(alias="iconUrl", description="Custom bot icon URL") + ] = None + + class UpdateMonitorAuthRequest(BaseModel): model_config = ConfigDict(extra="forbid", populate_by_name=True) config: ApiKeyAuthConfig | BasicAuthConfig | BearerAuthConfig | HeaderAuthConfig +class UpdateOpsGenieChannelConfig(BaseModel): + model_config = ConfigDict(extra="forbid", populate_by_name=True) + channel_type: Annotated[Literal["opsgenie"], Field(alias="channelType")] = ( + "opsgenie" + ) + api_key: Annotated[ + str | None, + Field(alias="apiKey", description="OpsGenie API key for alert creation"), + ] = None + region: Annotated[ + str | None, Field(description="OpsGenie API region: us or eu") + ] = None + + class UpdateOrgDetailsRequest(BaseModel): model_config = ConfigDict(extra="forbid", populate_by_name=True) name: Annotated[ @@ -5614,6 +6791,102 @@ class UpdateOrgDetailsRequest(BaseModel): ] = None +class UpdatePagerDutyChannelConfig(BaseModel): + model_config = ConfigDict(extra="forbid", populate_by_name=True) + channel_type: Annotated[Literal["pagerduty"], Field(alias="channelType")] = ( + "pagerduty" + ) + routing_key: Annotated[ + str | None, + Field( + alias="routingKey", + description="PagerDuty Events API v2 routing (integration) key", + ), + ] = None + severity_override: Annotated[ + str | None, + Field( + alias="severityOverride", description="Override PagerDuty severity mapping" + ), + ] = None + + +class UpdatePhoneCallChannelConfig(BaseModel): + model_config = ConfigDict(extra="forbid", populate_by_name=True) + channel_type: Annotated[Literal["phone_call"], Field(alias="channelType")] = ( + "phone_call" + ) + phone_number: Annotated[ + str | None, + Field( + alias="phoneNumber", + description="Recipient phone number in E.164 format; null preserves current", + ), + ] = None + verified_phone_number_id: Annotated[ + int | None, + Field( + alias="verifiedPhoneNumberId", + description="Id of an org verified_phone_number row; null preserves current when phoneNumber also null", + ), + ] = None + phone_numbers: Annotated[ + list[str] | None, + Field(alias="phoneNumbers", description="Deprecated: use phoneNumber"), + ] = None + voice_language: Annotated[ + str | None, + Field( + alias="voiceLanguage", + description="TTS voice language/locale (default: en-US). See VoiceLanguage for supported values", + ), + ] = None + preferred_language: Annotated[ + str | None, + Field( + alias="preferredLanguage", + description="Preferred language for TTS and notifications (BCP-47, e.g. en-US, de-DE). Alias for voiceLanguage", + ), + ] = None + + +class UpdatePushbulletChannelConfig(BaseModel): + model_config = ConfigDict(extra="forbid", populate_by_name=True) + channel_type: Annotated[Literal["pushbullet"], Field(alias="channelType")] = ( + "pushbullet" + ) + access_token: Annotated[ + str | None, Field(alias="accessToken", description="Pushbullet access token") + ] = None + device_iden: Annotated[ + str | None, + Field( + alias="deviceIden", + description="Target device identifier (broadcasts to all if empty)", + ), + ] = None + + +class UpdatePushoverChannelConfig(BaseModel): + model_config = ConfigDict(extra="forbid", populate_by_name=True) + channel_type: Annotated[Literal["pushover"], Field(alias="channelType")] = ( + "pushover" + ) + user_key: Annotated[ + str | None, Field(alias="userKey", description="Pushover user or group key") + ] = None + app_token: Annotated[ + str | None, + Field(alias="appToken", description="Pushover application API token"), + ] = None + priority: Annotated[ + str | None, Field(description="Notification priority override (-2 to 2)") + ] = None + sound: Annotated[str | None, Field(description="Notification sound override")] = ( + None + ) + + class UpdateResourceGroupRequest(BaseModel): model_config = ConfigDict(extra="forbid", populate_by_name=True) name: Annotated[ @@ -5718,6 +6991,21 @@ class UpdateResourceGroupRequest(BaseModel): ] = None +class UpdateRootlyChannelConfig(BaseModel): + model_config = ConfigDict(extra="forbid", populate_by_name=True) + channel_type: Annotated[Literal["rootly"], Field(alias="channelType")] = "rootly" + api_key: Annotated[ + str | None, + Field( + alias="apiKey", + description="Rootly API token with incident creation permission", + ), + ] = None + severity: Annotated[ + str | None, Field(description="Severity slug override (e.g. sev0, sev1)") + ] = None + + class UpdateSecretRequest(BaseModel): model_config = ConfigDict(extra="forbid", populate_by_name=True) value: Annotated[ @@ -5730,6 +7018,69 @@ class UpdateSecretRequest(BaseModel): ] +class UpdateSlackChannelConfig(BaseModel): + model_config = ConfigDict(extra="forbid", populate_by_name=True) + channel_type: Annotated[Literal["slack"], Field(alias="channelType")] = "slack" + webhook_url: Annotated[ + str | None, Field(alias="webhookUrl", description="Slack incoming webhook URL") + ] = None + mention_text: Annotated[ + str | None, + Field( + alias="mentionText", + description="Optional mention text included in notifications, e.g. @channel", + ), + ] = None + + +class UpdateSmsChannelConfig(BaseModel): + model_config = ConfigDict(extra="forbid", populate_by_name=True) + channel_type: Annotated[Literal["sms"], Field(alias="channelType")] = "sms" + phone_number: Annotated[ + str | None, + Field( + alias="phoneNumber", + description="Recipient phone number in E.164 format; null preserves current", + ), + ] = None + verified_phone_number_id: Annotated[ + int | None, + Field( + alias="verifiedPhoneNumberId", + description="Id of an org verified_phone_number row; null preserves current when phoneNumber also null", + ), + ] = None + phone_numbers: Annotated[ + list[str] | None, + Field(alias="phoneNumbers", description="Deprecated: use phoneNumber"), + ] = None + preferred_language: Annotated[ + str | None, + Field( + alias="preferredLanguage", + description="Preferred language for SMS body (BCP-47, e.g. en-US, de-DE). Default: en-US", + ), + ] = None + + +class UpdateSplunkOnCallChannelConfig(BaseModel): + model_config = ConfigDict(extra="forbid", populate_by_name=True) + channel_type: Annotated[Literal["splunk_oncall"], Field(alias="channelType")] = ( + "splunk_oncall" + ) + api_key: Annotated[ + str | None, Field(alias="apiKey", description="Splunk On-Call REST API key") + ] = None + routing_key: Annotated[ + str, + Field( + alias="routingKey", + description="Routing key for alert routing", + min_length=1, + ), + ] + + class UpdateStatusPageComponentGroupRequest(BaseModel): model_config = ConfigDict(extra="forbid", populate_by_name=True) name: Annotated[ @@ -5826,6 +7177,13 @@ class UpdateStatusPageComponentRequest(BaseModel): ] = None +class Status9(StrEnum): + investigating = "INVESTIGATING" + identified = "IDENTIFIED" + monitoring = "MONITORING" + resolved = "RESOLVED" + + class UpdateStatusPageIncidentRequest(BaseModel): model_config = ConfigDict(extra="forbid", populate_by_name=True) title: Annotated[ @@ -5837,7 +7195,7 @@ class UpdateStatusPageIncidentRequest(BaseModel): ), ] = None status: Annotated[ - Status6 | None, Field(description="New status; null preserves current") + Status9 | None, Field(description="New status; null preserves current") ] = None impact: Annotated[ Impact | None, Field(description="New impact level; null preserves current") @@ -5922,6 +7280,57 @@ class UpdateTagRequest(BaseModel): ] = None +class UpdateTeamsChannelConfig(BaseModel): + model_config = ConfigDict(extra="forbid", populate_by_name=True) + channel_type: Annotated[Literal["teams"], Field(alias="channelType")] = "teams" + webhook_url: Annotated[ + str | None, + Field(alias="webhookUrl", description="Microsoft Teams incoming webhook URL"), + ] = None + + +class UpdateTelegramChannelConfig(BaseModel): + model_config = ConfigDict(extra="forbid", populate_by_name=True) + channel_type: Annotated[Literal["telegram"], Field(alias="channelType")] = ( + "telegram" + ) + bot_token: Annotated[ + str | None, + Field(alias="botToken", description="Telegram bot token from @BotFather"), + ] = None + chat_id: Annotated[ + str, + Field( + alias="chatId", + description="Chat, group, or channel ID to send alerts to", + min_length=1, + ), + ] + + +class UpdateWebhookChannelConfig(BaseModel): + model_config = ConfigDict(extra="forbid", populate_by_name=True) + channel_type: Annotated[Literal["webhook"], Field(alias="channelType")] = "webhook" + url: Annotated[ + str | None, + Field(description="Webhook endpoint URL that receives alert payloads"), + ] = None + signing_secret: Annotated[ + str | None, + Field( + alias="signingSecret", + description="HMAC secret for X-DevHelm-Signature header; omit for unsigned delivery", + ), + ] = None + custom_headers: Annotated[ + dict[str, str] | None, + Field( + alias="customHeaders", + description="Additional HTTP headers to include in webhook requests", + ), + ] = None + + class UpdateWebhookEndpointRequest(BaseModel): model_config = ConfigDict(extra="forbid", populate_by_name=True) url: Annotated[ @@ -5960,6 +7369,15 @@ class UpdateWorkspaceRequest(BaseModel): ] +class UpdateZapierChannelConfig(BaseModel): + model_config = ConfigDict(extra="forbid", populate_by_name=True) + channel_type: Annotated[Literal["zapier"], Field(alias="channelType")] = "zapier" + webhook_url: Annotated[ + str | None, + Field(alias="webhookUrl", description="Zapier/n8n/Make catch webhook URL"), + ] = None + + class UptimeBucketDto(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) timestamp: Annotated[ @@ -6029,6 +7447,32 @@ class UptimeDto(BaseModel): examples=[312], ), ] = None + p50_latency_ms: Annotated[ + float | None, + Field( + alias="p50LatencyMs", + description="50th-percentile (median) latency in milliseconds; null when no data", + examples=[128], + ), + ] = None + incident_count: Annotated[ + int, + Field( + alias="incidentCount", + description="Number of incidents that started within the requested window", + examples=[2], + ), + ] + + +class VoiceLanguageDto(BaseModel): + model_config = ConfigDict(extra="ignore", populate_by_name=True) + code: Annotated[ + str, Field(description="BCP-47 locale code, e.g. en-US", min_length=1) + ] + label: Annotated[ + str, Field(description="Human-readable label, e.g. English (US)", min_length=1) + ] class WebhookChannelConfig(BaseModel): @@ -6045,7 +7489,7 @@ class WebhookChannelConfig(BaseModel): str | None, Field( alias="signingSecret", - description="Optional HMAC signing secret for payload verification", + description="HMAC secret for X-DevHelm-Signature header; omit for unsigned delivery", ), ] = None custom_headers: Annotated[ @@ -6201,6 +7645,20 @@ class ZapierChannelConfig(BaseModel): ] +class AcknowledgeAllIncidentsResponse(BaseModel): + model_config = ConfigDict(extra="ignore", populate_by_name=True) + acknowledged: Annotated[ + list[NotificationDispatchDto], + Field(description="Dispatches successfully acknowledged in this request"), + ] + skipped: Annotated[ + list[SkippedDispatch], + Field( + description="Dispatches skipped (already acked or not in an acknowledgeable state)" + ), + ] + + class AddMonitorTagsRequest(BaseModel): model_config = ConfigDict(extra="forbid", populate_by_name=True) tag_ids: Annotated[ @@ -6273,9 +7731,43 @@ class BulkMonitorActionResult(BaseModel): failed: Annotated[ list[FailureDetail], Field( - description="Monitors on which the action failed, with the reason for each failure" + description="Monitors on which the action failed, with the reason for each failure" + ), + ] + + +class Code(BaseModel): + model_config = ConfigDict(extra="forbid", populate_by_name=True) + check_type: Literal["code"] = "code" + exit_code: Annotated[ + int, Field(alias="exitCode", description="Container exit code (0 = pass)") + ] + stdout_snippet: Annotated[ + str | None, + Field(alias="stdoutSnippet", description="Truncated stdout from the container"), + ] = None + stderr_snippet: Annotated[ + str | None, + Field(alias="stderrSnippet", description="Truncated stderr from the container"), + ] = None + steps: Annotated[ + list[CodeCheckStep] | None, + Field(description="Named steps extracted from Playwright test output"), + ] = None + failure_kind: Annotated[ + str | None, + Field( + alias="failureKind", + description="Failure classification: timeout, assertion, or error", ), - ] + ] = None + timed_out: Annotated[ + bool | None, + Field( + alias="timedOut", + description="Whether the run hit a step/total/run-budget timeout", + ), + ] = None class ComponentUptimeDayDto(BaseModel): @@ -6342,10 +7834,12 @@ class CreateAlertChannelRequest(BaseModel): | MattermostChannelConfig | OpsGenieChannelConfig | PagerDutyChannelConfig + | PhoneCallChannelConfig | PushbulletChannelConfig | PushoverChannelConfig | RootlyChannelConfig | SlackChannelConfig + | SmsChannelConfig | SplunkOnCallChannelConfig | TeamsChannelConfig | TelegramChannelConfig @@ -6434,6 +7928,7 @@ class CreateMonitorRequest(BaseModel): | HttpMonitorConfig | IcmpMonitorConfig | McpServerMonitorConfig + | ScriptMonitorConfig | TcpMonitorConfig ) frequency_seconds: Annotated[ @@ -6640,6 +8135,56 @@ class CreateStatusPageRequest(BaseModel): ] = None +class CreditPolicy(BaseModel): + model_config = ConfigDict(extra="forbid", populate_by_name=True) + summary: Annotated[ + str | None, Field(description="Brief summary of credit policy") + ] = None + max_credit_percent: Annotated[ + int | None, + Field( + alias="maxCreditPercent", description="Max credit as percent of monthly fee" + ), + ] = None + claim_window_days: Annotated[ + int | None, + Field( + alias="claimWindowDays", + description="Days to submit a credit claim after eligibility", + ), + ] = None + credit_application_days: Annotated[ + int | None, + Field( + alias="creditApplicationDays", + description="Days for credit to be applied after approval", + ), + ] = None + tiers: Annotated[ + list[CreditTier] | None, Field(description="Credit tiers by uptime threshold") + ] = None + + +class CursorPageIncidentActivityEventDto(BaseModel): + model_config = ConfigDict(extra="ignore", populate_by_name=True) + data: Annotated[ + list[IncidentActivityEventDto], Field(description="Items on this page") + ] + next_cursor: Annotated[ + str | None, + Field( + alias="nextCursor", + description="Opaque cursor for the next page; null when there are no more results", + ), + ] = None + has_more: Annotated[ + bool, + Field( + alias="hasMore", description="Whether more results exist beyond this page" + ), + ] + + class CursorPageServiceCatalogDto(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) data: Annotated[list[ServiceCatalogDto], Field(description="Items on this page")] @@ -6676,6 +8221,24 @@ class CursorPageServicePollResultDto(BaseModel): ] +class CursorPageStatusEventDto(BaseModel): + model_config = ConfigDict(extra="ignore", populate_by_name=True) + data: Annotated[list[StatusEventDto], Field(description="Items on this page")] + next_cursor: Annotated[ + str | None, + Field( + alias="nextCursor", + description="Opaque cursor for the next page; null when there are no more results", + ), + ] = None + has_more: Annotated[ + bool, + Field( + alias="hasMore", description="Whether more results exist beyond this page" + ), + ] + + class DashboardOverviewDto(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) monitors: MonitorsSummaryDto @@ -6784,6 +8347,7 @@ class IncidentDetailDto(BaseModel): status_page_incidents: Annotated[ list[LinkedStatusPageIncidentDto] | None, Field(alias="statusPageIncidents") ] = None + trigger: IncidentTriggerDto | None = None class IncidentPolicyDto(BaseModel): @@ -7004,9 +8568,6 @@ class MonitorDto(BaseModel): """Note: ``currentStatus`` was removed from this DTO. Inspect ``enabled`` and the incident-policy API to derive a live status for a monitor instead.""" model_config = ConfigDict(extra="ignore", populate_by_name=True) - """Note: ``currentStatus`` was removed from this DTO. Inspect ``enabled`` and the incident-policy API to derive a live status for a monitor instead.""" - - model_config = ConfigDict(extra="forbid", populate_by_name=True) id: Annotated[UUID, Field(description="Unique monitor identifier")] organization_id: Annotated[ int, @@ -7024,6 +8585,7 @@ class MonitorDto(BaseModel): | HttpMonitorConfig | IcmpMonitorConfig | McpServerMonitorConfig + | ScriptMonitorConfig | TcpMonitorConfig ) frequency_seconds: Annotated[ @@ -7100,6 +8662,7 @@ class MonitorTestRequest(BaseModel): | HttpMonitorConfig | IcmpMonitorConfig | McpServerMonitorConfig + | ScriptMonitorConfig | TcpMonitorConfig ) assertions: Annotated[ @@ -7287,48 +8850,6 @@ class ResourceGroupDto(BaseModel): ] -class ServiceDetailDto(BaseModel): - model_config = ConfigDict(extra="ignore", populate_by_name=True) - id: UUID - slug: str - name: str - category: str | None = None - official_status_url: Annotated[str | None, Field(alias="officialStatusUrl")] = None - developer_context: Annotated[str | None, Field(alias="developerContext")] = None - logo_url: Annotated[str | None, Field(alias="logoUrl")] = None - adapter_type: Annotated[str, Field(alias="adapterType")] - polling_interval_seconds: Annotated[int, Field(alias="pollingIntervalSeconds")] - lifecycle_status: Annotated[ - str, - Field( - alias="lifecycleStatus", - description="Service lifecycle state: ACTIVE, DEGRADED, DEPRECATED, or RETIRED", - ), - ] - enabled: bool - created_at: Annotated[AwareDatetime, Field(alias="createdAt")] - updated_at: Annotated[AwareDatetime, Field(alias="updatedAt")] - current_status: Annotated[ServiceStatusDto | None, Field(alias="currentStatus")] = ( - None - ) - recent_incidents: Annotated[ - list[ServiceIncidentDto], Field(alias="recentIncidents") - ] - components: list[ServiceComponentDto] - components_summary: Annotated[ - ComponentsSummaryDto | None, Field(alias="componentsSummary") - ] = None - uptime: ComponentUptimeSummaryDto | None = None - active_maintenances: Annotated[ - list[ScheduledMaintenanceDto], Field(alias="activeMaintenances") - ] - data_completeness: Annotated[str, Field(alias="dataCompleteness")] - seo_metadata: Annotated[SeoMetadataDto | None, Field(alias="seoMetadata")] = None - related_services: Annotated[ - list[ServiceCatalogDto] | None, Field(alias="relatedServices") - ] = None - - class ServiceIncidentDetailDto(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) id: UUID @@ -7342,6 +8863,7 @@ class ServiceIncidentDetailDto(BaseModel): affected_components: Annotated[ list[str] | None, Field(alias="affectedComponents") ] = None + affected_regions: Annotated[list[str] | None, Field(alias="affectedRegions")] = None updates: list[ServiceIncidentUpdateDto] @@ -7372,6 +8894,11 @@ class ServiceUptimeResponse(BaseModel): ] = None +class SingleValueResponseAcknowledgeAllIncidentsResponse(BaseModel): + model_config = ConfigDict(extra="ignore", populate_by_name=True) + data: AcknowledgeAllIncidentsResponse + + class SingleValueResponseAuthMeResponse(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) data: AuthMeResponse @@ -7432,11 +8959,6 @@ class SingleValueResponseResourceGroupDto(BaseModel): data: ResourceGroupDto -class SingleValueResponseServiceDetailDto(BaseModel): - model_config = ConfigDict(extra="ignore", populate_by_name=True) - data: ServiceDetailDto - - class SingleValueResponseServiceIncidentDetailDto(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) data: ServiceIncidentDetailDto @@ -7467,6 +8989,11 @@ class SingleValueResponseStatusPageDto(BaseModel): data: StatusPageDto +class SingleValueResponseStatusPageNotificationDeliveryDto(BaseModel): + model_config = ConfigDict(extra="ignore", populate_by_name=True) + data: StatusPageNotificationDeliveryDto + + class SingleValueResponseStatusPageSubscriberDto(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) data: StatusPageSubscriberDto @@ -7512,6 +9039,48 @@ class SingleValueResponseWorkspaceDto(BaseModel): data: WorkspaceDto +class SlaDataDto(BaseModel): + model_config = ConfigDict(extra="ignore", populate_by_name=True) + sla_type: Annotated[ + str | None, + Field( + alias="slaType", + description="SLA pattern: plan_gated, per_service, no_public_sla, or universal", + ), + ] = None + official_sla: Annotated[OfficialSla | None, Field(alias="officialSla")] = None + service_breakdown: Annotated[ + list[ServiceBreakdown] | None, + Field( + alias="serviceBreakdown", + description="Per-service breakdown for vendors with per_service SLA type", + ), + ] = None + pricing_tiers: Annotated[ + list[PricingTier] | None, + Field( + alias="pricingTiers", description="Pricing tiers with associated SLA levels" + ), + ] = None + credit_policy: Annotated[CreditPolicy | None, Field(alias="creditPolicy")] = None + no_sla_context: Annotated[NoSlaContext | None, Field(alias="noSlaContext")] = None + source_urls: Annotated[SourceUrls | None, Field(alias="sourceUrls")] = None + last_researched: Annotated[ + str | None, + Field( + alias="lastResearched", + description="ISO date when this data was last manually researched", + ), + ] = None + research_notes: Annotated[ + str | None, + Field( + alias="researchNotes", + description="Freeform operator notes about the research", + ), + ] = None + + class StatusPageIncidentDto(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) id: UUID @@ -7540,6 +9109,39 @@ class StatusPageIncidentDto(BaseModel): updated_at: Annotated[AwareDatetime, Field(alias="updatedAt")] +class StatusPageMeasuredComponentUptimeDto(BaseModel): + model_config = ConfigDict(extra="ignore", populate_by_name=True) + source: Annotated[ + str, + Field( + description="Uptime source discriminator; always measured for this resource" + ), + ] + component_id: Annotated[ + UUID, Field(alias="componentId", description="Status-page component ID") + ] + monitor_id: Annotated[ + UUID, + Field( + alias="monitorId", + description="Linked monitor whose check rollups feed this series", + ), + ] + tracking_since: Annotated[ + str | None, + Field( + alias="trackingSince", + description="ISO-8601 date bars start (Camp A tracking-since); null only if unresolved", + ), + ] = None + days: Annotated[ + list[StatusPageMeasuredUptimeDayDto], + Field( + description="Dense daily buckets from tracking start through today (oldest → newest)" + ), + ] + + class TableValueResultComponentUptimeDayDto(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) data: list[ComponentUptimeDayDto] @@ -7621,6 +9223,24 @@ class TableValueResultTagDto(BaseModel): total_pages: Annotated[int | None, Field(alias="totalPages")] = None +class TableValueResultTestChannelResult(BaseModel): + model_config = ConfigDict(extra="ignore", populate_by_name=True) + data: list[TestChannelResult] + has_next: Annotated[bool, Field(alias="hasNext")] + has_prev: Annotated[bool, Field(alias="hasPrev")] + total_elements: Annotated[int | None, Field(alias="totalElements")] = None + total_pages: Annotated[int | None, Field(alias="totalPages")] = None + + +class TableValueResultVoiceLanguageDto(BaseModel): + model_config = ConfigDict(extra="ignore", populate_by_name=True) + data: list[VoiceLanguageDto] + has_next: Annotated[bool, Field(alias="hasNext")] + has_prev: Annotated[bool, Field(alias="hasPrev")] + total_elements: Annotated[int | None, Field(alias="totalElements")] = None + total_pages: Annotated[int | None, Field(alias="totalPages")] = None + + class TableValueResultWebhookDeliveryDto(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) data: list[WebhookDeliveryDto] @@ -7662,10 +9282,12 @@ class TestAlertChannelRequest(BaseModel): | MattermostChannelConfig | OpsGenieChannelConfig | PagerDutyChannelConfig + | PhoneCallChannelConfig | PushbulletChannelConfig | PushoverChannelConfig | RootlyChannelConfig | SlackChannelConfig + | SmsChannelConfig | SplunkOnCallChannelConfig | TeamsChannelConfig | TelegramChannelConfig @@ -7686,26 +9308,28 @@ class UpdateAlertChannelRequest(BaseModel): ), ] config: Annotated[ - DatadogChannelConfig - | DiscordChannelConfig - | EmailChannelConfig - | GitLabChannelConfig - | GoogleChatChannelConfig - | IncidentIoChannelConfig - | JiraChannelConfig - | LinearChannelConfig - | MattermostChannelConfig - | OpsGenieChannelConfig - | PagerDutyChannelConfig - | PushbulletChannelConfig - | PushoverChannelConfig - | RootlyChannelConfig - | SlackChannelConfig - | SplunkOnCallChannelConfig - | TeamsChannelConfig - | TelegramChannelConfig - | WebhookChannelConfig - | ZapierChannelConfig, + UpdateDatadogChannelConfig + | UpdateDiscordChannelConfig + | UpdateEmailChannelConfig + | UpdateGitLabChannelConfig + | UpdateGoogleChatChannelConfig + | UpdateIncidentIoChannelConfig + | UpdateJiraChannelConfig + | UpdateLinearChannelConfig + | UpdateMattermostChannelConfig + | UpdateOpsGenieChannelConfig + | UpdatePagerDutyChannelConfig + | UpdatePhoneCallChannelConfig + | UpdatePushbulletChannelConfig + | UpdatePushoverChannelConfig + | UpdateRootlyChannelConfig + | UpdateSlackChannelConfig + | UpdateSmsChannelConfig + | UpdateSplunkOnCallChannelConfig + | UpdateTeamsChannelConfig + | UpdateTelegramChannelConfig + | UpdateWebhookChannelConfig + | UpdateZapierChannelConfig, Field(discriminator="channel_type"), ] managed_by: Annotated[ @@ -7715,6 +9339,12 @@ class UpdateAlertChannelRequest(BaseModel): description="New attribution source: DASHBOARD, CLI, TERRAFORM, MCP, or API; null preserves current value.", ), ] = None + enabled: Annotated[ + bool | None, + Field( + description="Whether this channel is enabled (default: true); null preserves current value" + ), + ] = None class UpdateMonitorRequest(BaseModel): @@ -7733,6 +9363,7 @@ class UpdateMonitorRequest(BaseModel): | HttpMonitorConfig | IcmpMonitorConfig | McpServerMonitorConfig + | ScriptMonitorConfig | TcpMonitorConfig | None ) = None @@ -7906,9 +9537,9 @@ class CheckTraceDto(BaseModel): ] = None -class CheckTypeDetailsDto(RootModel[Http | Tcp | Icmp | Dns | McpServer]): +class CheckTypeDetailsDto(RootModel[Http | Tcp | Icmp | Dns | McpServer | Code]): root: Annotated[ - Http | Tcp | Icmp | Dns | McpServer, + Http | Tcp | Icmp | Dns | McpServer | Code, Field( description="Check-type-specific details — polymorphic by check_type discriminator", discriminator="check_type", @@ -7945,6 +9576,56 @@ class CreateNotificationPolicyRequest(BaseModel): ] = 0 +class ServiceDetailDto(BaseModel): + model_config = ConfigDict(extra="ignore", populate_by_name=True) + id: UUID + slug: str + name: str + category: str | None = None + official_status_url: Annotated[str | None, Field(alias="officialStatusUrl")] = None + developer_context: Annotated[str | None, Field(alias="developerContext")] = None + logo_url: Annotated[str | None, Field(alias="logoUrl")] = None + adapter_type: Annotated[str, Field(alias="adapterType")] + polling_interval_seconds: Annotated[int, Field(alias="pollingIntervalSeconds")] + lifecycle_status: Annotated[ + str, + Field( + alias="lifecycleStatus", + description="Service lifecycle state: ACTIVE, DEGRADED, DEPRECATED, or RETIRED", + ), + ] + enabled: bool + created_at: Annotated[AwareDatetime, Field(alias="createdAt")] + updated_at: Annotated[AwareDatetime, Field(alias="updatedAt")] + current_status: Annotated[ServiceStatusDto | None, Field(alias="currentStatus")] = ( + None + ) + recent_incidents: Annotated[ + list[ServiceIncidentDto], Field(alias="recentIncidents") + ] + components: list[ServiceComponentDto] + components_summary: Annotated[ + ComponentsSummaryDto | None, Field(alias="componentsSummary") + ] = None + uptime: ComponentUptimeSummaryDto | None = None + active_maintenances: Annotated[ + list[ScheduledMaintenanceDto], Field(alias="activeMaintenances") + ] + data_completeness: Annotated[str, Field(alias="dataCompleteness")] + sla_published: Annotated[ + bool, + Field( + alias="slaPublished", + description="Whether the service's SLA page is publicly visible", + ), + ] + seo_metadata: Annotated[SeoMetadataDto | None, Field(alias="seoMetadata")] = None + sla_data: Annotated[SlaDataDto | None, Field(alias="slaData")] = None + related_services: Annotated[ + list[ServiceCatalogDto] | None, Field(alias="relatedServices") + ] = None + + class SingleValueResponseBatchComponentUptimeDto(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) data: BatchComponentUptimeDto @@ -7955,11 +9636,21 @@ class SingleValueResponseCheckTraceDto(BaseModel): data: CheckTraceDto +class SingleValueResponseServiceDetailDto(BaseModel): + model_config = ConfigDict(extra="ignore", populate_by_name=True) + data: ServiceDetailDto + + class SingleValueResponseStatusPageIncidentDto(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) data: StatusPageIncidentDto +class SingleValueResponseStatusPageMeasuredComponentUptimeDto(BaseModel): + model_config = ConfigDict(extra="ignore", populate_by_name=True) + data: StatusPageMeasuredComponentUptimeDto + + class TableValueResultAuditEventDto(BaseModel): model_config = ConfigDict(extra="ignore", populate_by_name=True) data: list[AuditEventDto]