openapi: 3.1.0
info:
  title: Signal Cloud API
  version: 1.0.0
  description: >-
    Authenticated Console-facing Cloud API for event exploration, analytics,
    detection, notifications, maintenance, and server status. Event ingestion,
    adapter recovery, health, identity, administration, and operator operation
    endpoints are intentionally outside this document.
servers:
  - url: https://{cloudHost}
    description: Signal Cloud deployment
    variables:
      cloudHost:
        default: cloud.example.com
        description: Hostname of the Signal Cloud deployment.
tags:
  - name: Events
    description: Tenant-scoped event exploration and filter values.
  - name: Analytics
    description: Projection-backed activity analytics and reports.
  - name: Server Status
    description: Tenant-scoped server-instance trust and maintenance state.
  - name: Detection
    description: Community-scoped detection rules, alerts, and occurrences.
  - name: Notifications
    description: Notification endpoints, delivery history, and replay.
  - name: Maintenance
    description: Community and server-instance maintenance windows.
paths:
  /v1/events:
    get:
      tags: [Events]
      operationId: listEvents
      summary: List or poll community events
      description: >-
        Returns a tenant-scoped event explorer page by default. Set `view=live`
        to use the live polling projection. Community scope is derived from
        the authenticated Console session.
      security:
        - signalSession: []
      parameters:
        - name: view
          in: query
          required: false
          description: Set to `live` for the live polling projection; omit for the explorer.
          schema:
            type: string
            enum: [live]
        - name: occurred_from
          in: query
          required: false
          description: Inclusive explorer range start. Required when `view` is omitted.
          schema:
            type: string
            format: date-time
        - name: occurred_to
          in: query
          required: false
          description: Exclusive explorer range end. Required when `view` is omitted.
          schema:
            type: string
            format: date-time
        - name: event_type
          in: query
          required: false
          description: Singular event-type filter alias.
          schema:
            type: string
        - name: event_types
          in: query
          required: false
          style: form
          explode: false
          description: Comma-separated event-type filters.
          schema:
            type: array
            items:
              type: string
        - name: server_id
          in: query
          required: false
          description: Singular server-id filter alias.
          schema:
            type: string
        - name: server_ids
          in: query
          required: false
          style: form
          explode: false
          description: Comma-separated server-id filters.
          schema:
            type: array
            items:
              type: string
        - name: server_instance_id
          in: query
          required: false
          schema:
            type: string
        - name: mission_id
          in: query
          required: false
          schema:
            type: string
        - name: mission_session_id
          in: query
          required: false
          schema:
            type: string
        - name: participant_entity_id
          in: query
          required: false
          description: Participant entity filter.
          schema:
            type: string
        - name: player_entity_id
          in: query
          required: false
          description: Alias for `participant_entity_id`.
          schema:
            type: string
        - name: player_session_id
          in: query
          required: false
          schema:
            type: string
        - name: spawn_session_id
          in: query
          required: false
          schema:
            type: string
        - name: origin
          in: query
          required: false
          schema:
            type: string
            enum: [adapter, cloud_derived]
        - name: schema_version
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
        - name: page_size
          in: query
          required: false
          description: Explorer page size, from 1 through 200.
          schema:
            type: integer
            minimum: 1
            maximum: 200
        - name: limit
          in: query
          required: false
          description: Live poll limit, from 1 through 200.
          schema:
            type: integer
            minimum: 1
            maximum: 200
        - name: cursor
          in: query
          required: false
          description: Opaque continuation cursor returned by the matching view.
          schema:
            type: string
            maxLength: 2048
      responses:
        '200':
          description: Event explorer page or live poll result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EventSearchResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '409':
          $ref: '#/components/responses/Conflict'
        '500':
          $ref: '#/components/responses/ServerError'
  /v1/events/{eventId}:
    get:
      tags: [Events]
      operationId: getEvent
      summary: Get canonical event detail
      security:
        - signalSession: []
      parameters:
        - $ref: '#/components/parameters/EventId'
      responses:
        '200':
          description: Canonical event document with Cloud receipt metadata.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EventDetailResponse'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/ServerError'
  /v1/events/filters/event-types:
    get:
      tags: [Events]
      operationId: listEventTypeFilters
      summary: List event-type filter values
      security:
        - signalSession: []
      parameters:
        - name: q
          in: query
          required: false
          schema:
            type: string
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
      responses:
        '200':
          description: Matching event-type values.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FilterValues'
        '500':
          $ref: '#/components/responses/ServerError'
  /v1/events/filters/servers:
    get:
      tags: [Events]
      operationId: listServerFilters
      summary: List server filter values
      security:
        - signalSession: []
      parameters:
        - name: q
          in: query
          required: false
          schema:
            type: string
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
      responses:
        '200':
          description: Matching server identifiers.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FilterValues'
        '500':
          $ref: '#/components/responses/ServerError'
  /v1/analytics/activity:
    get:
      tags: [Analytics]
      operationId: getCommunityActivityAnalytics
      summary: Get community activity analytics
      description: Requires the `analytics.read` permission.
      security:
        - signalSession: []
      parameters:
        - name: from
          in: query
          required: true
          schema:
            type: string
            format: date-time
        - name: to
          in: query
          required: true
          schema:
            type: string
            format: date-time
        - name: scope
          in: query
          required: true
          schema:
            type: string
            enum: [community]
      responses:
        '200':
          description: Projection-backed community activity summary.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CommunityAnalyticsResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/ServerError'
  /v1/player-sessions/{playerSessionId}/analytics:
    get:
      tags: [Analytics]
      operationId: getPlayerSessionAnalytics
      summary: Get player-session analytics
      description: Requires the `analytics.read` permission.
      security:
        - signalSession: []
      parameters:
        - $ref: '#/components/parameters/PlayerSessionId'
      responses:
        '200':
          description: Projection-backed player-session analytics.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlayerSessionAnalytics'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/ServerError'
  /v1/reports/community-activity.pdf:
    get:
      tags: [Analytics]
      operationId: downloadCommunityActivityReport
      summary: Download a community activity report
      description: Requires the `analytics.read` permission.
      security:
        - signalSession: []
      parameters:
        - name: from
          in: query
          required: true
          schema:
            type: string
            format: date-time
        - name: to
          in: query
          required: true
          schema:
            type: string
            format: date-time
      responses:
        '200':
          description: Community activity report PDF.
          content:
            application/pdf:
              schema:
                type: string
                format: binary
        '400':
          $ref: '#/components/responses/BadRequest'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/ServerError'
  /v1/server-instances/{serverInstanceId}/status:
    get:
      tags: [Server Status]
      operationId: getServerInstanceStatus
      summary: Get server-instance status
      description: Requires the `analytics.read` permission. The response includes recent Cloud-derived server operations and maintenance state.
      security:
        - signalSession: []
      parameters:
        - $ref: '#/components/parameters/ServerInstanceId'
      responses:
        '200':
          description: Server-instance trust and maintenance state.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ServerInstanceStatus'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/ServerError'
  /v1/detection/event-types:
    get:
      tags: [Detection]
      operationId: listDetectionEventTypes
      summary: List event types supported by detection rules
      description: Requires the `rules.read` permission.
      security:
        - signalSession: []
      responses:
        '200':
          description: Known detection event types.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DetectionEventTypesResponse'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/ServerError'
  /v1/detection/fields:
    get:
      tags: [Detection]
      operationId: listDetectionFields
      summary: List detection rule fields and operators
      description: Requires the `rules.read` permission.
      security:
        - signalSession: []
      responses:
        '200':
          description: Field metadata accepted by the detection rule editor.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DetectionFieldsResponse'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/ServerError'
  /v1/detection/rules:
    get:
      tags: [Detection]
      operationId: listDetectionRules
      summary: List detection rules
      description: Requires the `rules.read` permission.
      security:
        - signalSession: []
      parameters:
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
      responses:
        '200':
          description: Community-scoped detection rules.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DetectionRuleListResponse'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/ServerError'
    post:
      tags: [Detection]
      operationId: createDetectionRule
      summary: Create a detection rule
      description: Requires the `rules.write` permission. New rules are created disabled.
      security:
        - signalSession: []
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DetectionRuleWrite'
      responses:
        '201':
          description: Detection rule created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DetectionRuleMutationResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          $ref: '#/components/responses/Conflict'
        '500':
          $ref: '#/components/responses/ServerError'
  /v1/detection/rules/{ruleId}:
    get:
      tags: [Detection]
      operationId: getDetectionRule
      summary: Get a detection rule
      description: Requires the `rules.read` permission.
      security:
        - signalSession: []
      parameters:
        - $ref: '#/components/parameters/RuleId'
      responses:
        '200':
          description: Current detection rule revision.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DetectionRule'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/ServerError'
    put:
      tags: [Detection]
      operationId: updateDetectionRule
      summary: Update a detection rule
      description: Requires the `rules.write` permission. Updating a rule creates a new immutable revision.
      security:
        - signalSession: []
      parameters:
        - $ref: '#/components/parameters/RuleId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DetectionRuleWrite'
      responses:
        '200':
          description: Updated detection rule.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DetectionRuleEnvelope'
        '400':
          $ref: '#/components/responses/BadRequest'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '500':
          $ref: '#/components/responses/ServerError'
    delete:
      tags: [Detection]
      operationId: deleteDetectionRule
      summary: Delete a detection rule
      description: Requires the `rules.write` permission.
      security:
        - signalSession: []
      parameters:
        - $ref: '#/components/parameters/RuleId'
      responses:
        '204':
          description: Detection rule deleted.
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/ServerError'
  /v1/detection/rules/{ruleId}/enable:
    post:
      tags: [Detection]
      operationId: enableDetectionRule
      summary: Enable a detection rule
      description: Requires the `rules.write` permission.
      security:
        - signalSession: []
      parameters:
        - $ref: '#/components/parameters/RuleId'
      responses:
        '200':
          description: Detection rule enabled.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DetectionRuleEnvelope'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/ServerError'
  /v1/detection/rules/{ruleId}/disable:
    post:
      tags: [Detection]
      operationId: disableDetectionRule
      summary: Disable a detection rule
      description: Requires the `rules.write` permission.
      security:
        - signalSession: []
      parameters:
        - $ref: '#/components/parameters/RuleId'
      responses:
        '200':
          description: Detection rule disabled.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DetectionRuleEnvelope'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/ServerError'
  /v1/detection/rules/{ruleId}/archive:
    post:
      tags: [Detection]
      operationId: archiveDetectionRule
      summary: Archive a detection rule
      description: Requires the `rules.write` permission.
      security:
        - signalSession: []
      parameters:
        - $ref: '#/components/parameters/RuleId'
      responses:
        '200':
          description: Detection rule archived.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DetectionRuleEnvelope'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/ServerError'
  /v1/detection/rules/{ruleId}/duplicate:
    post:
      tags: [Detection]
      operationId: duplicateDetectionRule
      summary: Duplicate a detection rule
      description: Requires the `rules.write` permission. The duplicate is created disabled.
      security:
        - signalSession: []
      parameters:
        - $ref: '#/components/parameters/RuleId'
      responses:
        '200':
          description: Duplicated detection rule.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DetectionRuleEnvelope'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/ServerError'
  /v1/detection/occurrences:
    get:
      tags: [Detection]
      operationId: listDetectionOccurrences
      summary: List detection occurrences
      description: Requires the `alerts.read` permission.
      security:
        - signalSession: []
      parameters:
        - name: state
          in: query
          required: false
          schema:
            type: string
            enum: [open, resolved]
        - name: rule_id
          in: query
          required: false
          schema:
            type: string
        - name: severity
          in: query
          required: false
          schema:
            type: string
            enum: [info, low, medium, high, critical]
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
      responses:
        '200':
          description: Community-scoped detection occurrences.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DetectionOccurrenceListResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/ServerError'
  /v1/detection/occurrences/{occurrenceId}:
    get:
      tags: [Detection]
      operationId: getDetectionOccurrence
      summary: Get a detection occurrence
      description: Requires the `alerts.read` permission.
      security:
        - signalSession: []
      parameters:
        - $ref: '#/components/parameters/OccurrenceId'
      responses:
        '200':
          description: Detection occurrence with transition history.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DetectionOccurrenceDetail'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/ServerError'
  /v1/detection/protection-presets/server-uptime:
    get:
      tags: [Detection]
      operationId: getServerUptimePreset
      summary: Get the server-uptime protection preset
      description: Requires the `rules.read` permission.
      security:
        - signalSession: []
      responses:
        '200':
          description: Preview of the approved server-uptime detection rules.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ServerUptimePresetResponse'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/ServerError'
  /v1/detection/alerts:
    get:
      tags: [Detection]
      operationId: listDetectionAlerts
      summary: List detection alerts
      description: Requires the `alerts.read` permission.
      security:
        - signalSession: []
      parameters:
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
      responses:
        '200':
          description: Community-scoped detection alerts.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DetectionAlertListResponse'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/ServerError'
  /v1/detection/alerts/{alertId}:
    get:
      tags: [Detection]
      operationId: getDetectionAlert
      summary: Get a detection alert
      description: Requires the `alerts.read` permission.
      security:
        - signalSession: []
      parameters:
        - $ref: '#/components/parameters/AlertId'
      responses:
        '200':
          description: Detection alert detail.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DetectionAlert'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/ServerError'
  /v1/notifications/discord/endpoints:
    get:
      tags: [Notifications]
      operationId: listDiscordEndpoints
      summary: List Discord notification endpoints
      description: Requires the `webhooks.read` permission.
      security:
        - signalSession: []
      parameters:
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
      responses:
        '200':
          description: Community-scoped Discord endpoint summaries.
          content:
            application/json:
              schema:
                type: object
                required: [endpoints]
                properties:
                  endpoints:
                    type: array
                    items:
                      $ref: '#/components/schemas/NotificationEndpoint'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/ServerError'
    post:
      tags: [Notifications]
      operationId: createDiscordEndpoint
      summary: Create a Discord notification endpoint
      description: Requires the `webhooks.write` permission. The returned endpoint starts disabled.
      security:
        - signalSession: []
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DiscordEndpointCreateRequest'
      responses:
        '201':
          description: Discord endpoint created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DiscordEndpointCreateResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          $ref: '#/components/responses/Conflict'
        '500':
          $ref: '#/components/responses/ServerError'
  /v1/notifications/discord/endpoints/{endpointId}:
    get:
      tags: [Notifications]
      operationId: getDiscordEndpoint
      summary: Get a Discord notification endpoint
      description: Requires the `webhooks.read` permission. Destination credentials are never returned.
      security:
        - signalSession: []
      parameters:
        - $ref: '#/components/parameters/EndpointId'
      responses:
        '200':
          description: Discord endpoint configuration without its secret destination.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotificationEndpoint'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/ServerError'
  /v1/notifications/discord/endpoints/{endpointId}/disable:
    post:
      tags: [Notifications]
      operationId: disableDiscordEndpoint
      summary: Disable a Discord notification endpoint
      description: Requires the `webhooks.write` permission.
      security:
        - signalSession: []
      parameters:
        - $ref: '#/components/parameters/EndpointId'
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Discord endpoint disabled.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotificationStateResponse'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '500':
          $ref: '#/components/responses/ServerError'
  /v1/notifications/discord/endpoints/{endpointId}/archive:
    post:
      tags: [Notifications]
      operationId: archiveDiscordEndpoint
      summary: Archive a Discord notification endpoint
      description: Requires the `webhooks.write` permission.
      security:
        - signalSession: []
      parameters:
        - $ref: '#/components/parameters/EndpointId'
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Discord endpoint archived.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotificationStateResponse'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '500':
          $ref: '#/components/responses/ServerError'
  /v1/notifications/webhooks:
    get:
      tags: [Notifications]
      operationId: listWebhooks
      summary: List generic webhook endpoints
      description: Requires the `webhooks.read` permission.
      security:
        - signalSession: []
      parameters:
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
      responses:
        '200':
          description: Community-scoped generic webhook summaries.
          content:
            application/json:
              schema:
                type: object
                required: [webhooks]
                properties:
                  webhooks:
                    type: array
                    items:
                      $ref: '#/components/schemas/NotificationEndpoint'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/ServerError'
    post:
      tags: [Notifications]
      operationId: createWebhook
      summary: Create a generic webhook endpoint
      description: Requires the `webhooks.write` permission. The response contains the generated secret once; it is not returned again.
      security:
        - signalSession: []
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/GenericWebhookWrite'
      responses:
        '201':
          description: Generic webhook endpoint created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/GenericWebhookCreateResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          $ref: '#/components/responses/Conflict'
        '500':
          $ref: '#/components/responses/ServerError'
  /v1/notifications/webhooks/{endpointId}:
    get:
      tags: [Notifications]
      operationId: getWebhook
      summary: Get a generic webhook endpoint
      description: Requires the `webhooks.read` permission. Destination credentials are never returned.
      security:
        - signalSession: []
      parameters:
        - $ref: '#/components/parameters/EndpointId'
      responses:
        '200':
          description: Generic webhook configuration without its secret destination.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotificationEndpoint'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/ServerError'
  /v1/notifications/webhooks/{endpointId}/revisions:
    post:
      tags: [Notifications]
      operationId: createWebhookRevision
      summary: Create a webhook endpoint revision
      description: Requires the `webhooks.write` permission.
      security:
        - signalSession: []
      parameters:
        - $ref: '#/components/parameters/EndpointId'
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/GenericWebhookWrite'
      responses:
        '200':
          description: New webhook revision created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotificationRevisionResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '500':
          $ref: '#/components/responses/ServerError'
  /v1/notifications/webhooks/{endpointId}/enable:
    post:
      tags: [Notifications]
      operationId: enableWebhook
      summary: Enable a webhook endpoint
      description: Requires the `webhooks.write` permission.
      security:
        - signalSession: []
      parameters:
        - $ref: '#/components/parameters/EndpointId'
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Webhook endpoint enabled.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotificationStateResponse'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '500':
          $ref: '#/components/responses/ServerError'
  /v1/notifications/webhooks/{endpointId}/disable:
    post:
      tags: [Notifications]
      operationId: disableWebhook
      summary: Disable a webhook endpoint
      description: Requires the `webhooks.write` permission.
      security:
        - signalSession: []
      parameters:
        - $ref: '#/components/parameters/EndpointId'
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Webhook endpoint disabled.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotificationStateResponse'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '500':
          $ref: '#/components/responses/ServerError'
  /v1/notifications/webhooks/{endpointId}/archive:
    post:
      tags: [Notifications]
      operationId: archiveWebhook
      summary: Archive a webhook endpoint
      description: Requires the `webhooks.write` permission.
      security:
        - signalSession: []
      parameters:
        - $ref: '#/components/parameters/EndpointId'
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Webhook endpoint archived.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotificationStateResponse'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '500':
          $ref: '#/components/responses/ServerError'
  /v1/notifications/webhooks/{endpointId}/rotate-secret:
    post:
      tags: [Notifications]
      operationId: rotateWebhookSecret
      summary: Rotate a webhook secret
      description: Requires the `webhooks.write` permission. The new secret is returned once.
      security:
        - signalSession: []
      parameters:
        - $ref: '#/components/parameters/EndpointId'
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: New webhook secret issued.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotificationSecretResponse'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '500':
          $ref: '#/components/responses/ServerError'
  /v1/notifications/deliveries:
    get:
      tags: [Notifications]
      operationId: listNotificationDeliveries
      summary: List notification deliveries
      description: Requires the `deliveries.read` permission.
      security:
        - signalSession: []
      parameters:
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: days
          in: query
          required: false
          description: Optional client-side retention filter; maximum 31 days.
          schema:
            type: integer
            minimum: 1
            maximum: 31
            default: 31
        - name: endpoint_id
          in: query
          required: false
          schema:
            type: string
        - name: state
          in: query
          required: false
          schema:
            type: string
            enum: [pending, leased, succeeded, failed]
        - name: rule_id
          in: query
          required: false
          schema:
            type: string
        - name: severity
          in: query
          required: false
          schema:
            type: string
            enum: [info, low, medium, high, critical]
        - name: cursor
          in: query
          required: false
          schema:
            type: string
      responses:
        '200':
          description: Community-scoped notification deliveries.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotificationDeliveriesResponse'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/ServerError'
  /v1/notifications/deliveries/{deliveryId}:
    get:
      tags: [Notifications]
      operationId: getNotificationDelivery
      summary: Get a notification delivery
      description: Requires the `deliveries.read` permission.
      security:
        - signalSession: []
      parameters:
        - $ref: '#/components/parameters/DeliveryId'
      responses:
        '200':
          description: Notification delivery detail.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotificationDelivery'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/ServerError'
  /v1/notifications/deliveries/{deliveryId}/replay:
    post:
      tags: [Notifications]
      operationId: replayNotificationDelivery
      summary: Replay a failed notification delivery
      description: Requires the `deliveries.replay` permission. Only failed deliveries can be replayed.
      security:
        - signalSession: []
      parameters:
        - $ref: '#/components/parameters/DeliveryId'
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              properties:
                reason:
                  type: string
                  maxLength: 1024
      responses:
        '200':
          description: Replay operation accepted.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReplayResponse'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '500':
          $ref: '#/components/responses/ServerError'
  /v1/communities/{communityId}/maintenance:
    get:
      tags: [Maintenance]
      operationId: getCommunityMaintenance
      summary: Get community maintenance state
      description: Requires the `community.manage` permission. The community is checked against the active Console community.
      security:
        - signalSession: []
      parameters:
        - $ref: '#/components/parameters/CommunityId'
      responses:
        '200':
          description: Community maintenance state and windows.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CommunityMaintenanceResponse'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/ServerError'
    post:
      tags: [Maintenance]
      operationId: createCommunityMaintenance
      summary: Create a community maintenance window
      description: Requires the `community.manage` permission. The request must originate from the configured Console origin.
      security:
        - signalSession: []
      parameters:
        - $ref: '#/components/parameters/CommunityId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MaintenanceWindowCreate'
      responses:
        '201':
          description: Community maintenance window created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MaintenanceWindow'
        '400':
          $ref: '#/components/responses/BadRequest'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          $ref: '#/components/responses/Conflict'
        '500':
          $ref: '#/components/responses/ServerError'
  /v1/server-instances/{serverInstanceId}/maintenance:
    get:
      tags: [Maintenance]
      operationId: getServerInstanceMaintenance
      summary: Get server-instance maintenance state
      description: Requires the `analytics.read` permission.
      security:
        - signalSession: []
      parameters:
        - $ref: '#/components/parameters/ServerInstanceId'
      responses:
        '200':
          description: Server-instance maintenance state and windows.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ServerMaintenanceResponse'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/ServerError'
    post:
      tags: [Maintenance]
      operationId: createServerInstanceMaintenance
      summary: Create a server-instance maintenance window
      description: Requires the `community.manage` permission. The request must originate from the configured Console origin.
      security:
        - signalSession: []
      parameters:
        - $ref: '#/components/parameters/ServerInstanceId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MaintenanceWindowCreate'
      responses:
        '201':
          description: Server-instance maintenance window created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MaintenanceWindow'
        '400':
          $ref: '#/components/responses/BadRequest'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          $ref: '#/components/responses/Conflict'
        '500':
          $ref: '#/components/responses/ServerError'
  /v1/maintenance/{windowId}:
    put:
      tags: [Maintenance]
      operationId: extendMaintenanceWindow
      summary: Extend a maintenance window
      description: Requires the `community.manage` permission. The request must originate from the configured Console origin.
      security:
        - signalSession: []
      parameters:
        - $ref: '#/components/parameters/WindowId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MaintenanceWindowUpdate'
      responses:
        '200':
          description: Updated maintenance window.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MaintenanceWindow'
        '400':
          $ref: '#/components/responses/BadRequest'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '500':
          $ref: '#/components/responses/ServerError'
    delete:
      tags: [Maintenance]
      operationId: stopMaintenanceWindow
      summary: Stop a maintenance window
      description: Requires the `community.manage` permission. The request must originate from the configured Console origin.
      security:
        - signalSession: []
      parameters:
        - $ref: '#/components/parameters/WindowId'
      responses:
        '204':
          description: Maintenance window stopped.
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/ServerError'
components:
  securitySchemes:
    signalSession:
      type: apiKey
      in: cookie
      name: signal_session
  parameters:
    EventId:
      name: eventId
      in: path
      required: true
      schema:
        type: string
    PlayerSessionId:
      name: playerSessionId
      in: path
      required: true
      schema:
        type: string
    ServerInstanceId:
      name: serverInstanceId
      in: path
      required: true
      schema:
        type: string
    RuleId:
      name: ruleId
      in: path
      required: true
      schema:
        type: string
    OccurrenceId:
      name: occurrenceId
      in: path
      required: true
      schema:
        type: string
    AlertId:
      name: alertId
      in: path
      required: true
      schema:
        type: string
    EndpointId:
      name: endpointId
      in: path
      required: true
      schema:
        type: string
    DeliveryId:
      name: deliveryId
      in: path
      required: true
      schema:
        type: string
    CommunityId:
      name: communityId
      in: path
      required: true
      schema:
        type: string
    WindowId:
      name: windowId
      in: path
      required: true
      schema:
        type: string
    IdempotencyKey:
      name: idempotency-key
      in: header
      required: true
      description: Stable caller-generated key for an idempotent mutation.
      schema:
        type: string
        minLength: 1
        maxLength: 255
  responses:
    BadRequest:
      description: Request validation failed.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/CloudError'
    Forbidden:
      description: The authenticated caller lacks the required community permission or scope.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/CloudError'
    NotFound:
      description: The requested resource was not found in the authenticated community.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/CloudError'
    Conflict:
      description: The request conflicts with current state or an idempotency record.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/CloudError'
    ServerError:
      description: Signal Cloud could not complete the request.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/CloudError'
  schemas:
    CloudError:
      type: object
      additionalProperties: false
      required: [status, code, message, request_id, retryable]
      properties:
        status:
          const: error
        code:
          type: string
        message:
          type: string
        request_id:
          type: string
        retryable:
          type: boolean
    EventSummary:
      type: object
      additionalProperties: false
      required: [event_id, community_id, occurred_at, received_at, server_id, server_instance_id, event_type, schema_version, origin, sequence, participant_entity_ids, first_indexed_at]
      properties:
        event_id:
          type: string
        community_id:
          type: string
        occurred_at:
          type: string
          format: date-time
        received_at:
          type: string
          format: date-time
        server_id:
          type: string
        server_instance_id:
          type: string
        mission_id:
          type: [string, 'null']
        mission_session_id:
          type: [string, 'null']
        event_type:
          type: string
        schema_version:
          type: integer
        origin:
          type: string
          enum: [adapter, cloud_derived]
        sequence:
          type: integer
        participant_entity_ids:
          type: array
          items:
            type: string
        player_session_id:
          type: [string, 'null']
        spawn_session_id:
          type: [string, 'null']
        first_indexed_at:
          type: string
          format: date-time
    EventExplorerResponse:
      type: object
      additionalProperties: false
      required: [events, page]
      properties:
        events:
          type: array
          items:
            $ref: '#/components/schemas/EventSummary'
        page:
          type: object
          additionalProperties: false
          required: [snapshot_at, next_cursor]
          properties:
            snapshot_at:
              type: string
              format: date-time
            next_cursor:
              type: [string, 'null']
    EventLiveResponse:
      type: object
      additionalProperties: false
      required: [events, live]
      properties:
        events:
          type: array
          items:
            $ref: '#/components/schemas/EventSummary'
        live:
          type: object
          additionalProperties: false
          required: [cursor, has_more, poll_after_ms]
          properties:
            cursor:
              type: string
            has_more:
              type: boolean
            poll_after_ms:
              type: integer
    EventSearchResponse:
      oneOf:
        - $ref: '#/components/schemas/EventExplorerResponse'
        - $ref: '#/components/schemas/EventLiveResponse'
    EventDetailResponse:
      type: object
      additionalProperties: false
      required: [event, received_at, origin]
      properties:
        event:
          type: object
          additionalProperties: true
        received_at:
          type: string
          format: date-time
        origin:
          type: string
          enum: [adapter, cloud_derived]
    FilterValues:
      type: object
      additionalProperties: false
      required: [values]
      properties:
        values:
          type: array
          items:
            type: string
    CommunityAnalyticsResponse:
      type: object
      additionalProperties: false
      required: [community_id, from, to, as_of, definition_version, freshness, summary, buckets]
      properties:
        community_id:
          type: string
        from:
          type: string
          format: date-time
        to:
          type: string
          format: date-time
        as_of:
          type: string
          format: date-time
        definition_version:
          type: integer
        freshness:
          type: object
          additionalProperties: false
          required: [summary, buckets]
          properties:
            summary:
              type: string
              enum: [fresh, delayed, stale]
            buckets:
              type: string
              enum: [fresh, delayed, stale]
        summary:
          type: object
          additionalProperties: false
          required: [accepted_event_count, unique_active_player_count, session_start_count, session_close_count]
          properties:
            accepted_event_count:
              type: integer
            unique_active_player_count:
              type: integer
            session_start_count:
              type: integer
            session_close_count:
              type: integer
            average_concurrency:
              type: [number, 'null']
        buckets:
          type: array
          items:
            $ref: '#/components/schemas/AnalyticsBucket'
    AnalyticsBucket:
      type: object
      additionalProperties: false
      required: [bucket_start, bucket_end, accepted_event_count, unique_active_player_count, session_start_count, session_close_count, freshness]
      properties:
        bucket_start:
          type: string
          format: date-time
        bucket_end:
          type: string
          format: date-time
        accepted_event_count:
          type: integer
        unique_active_player_count:
          type: integer
        session_start_count:
          type: integer
        session_close_count:
          type: integer
        freshness:
          type: string
          enum: [fresh, delayed, stale]
    PlayerSessionAnalytics:
      type: object
      additionalProperties: false
      required: [player_session_id, retention_30d, activity, lifecycle]
      properties:
        player_session_id:
          type: string
        player_entity_id:
          type: [string, 'null']
        server_id:
          type: [string, 'null']
        server_instance_id:
          type: [string, 'null']
        mission_id:
          type: [string, 'null']
        mission_session_id:
          type: [string, 'null']
        started_at:
          type: [string, 'null']
          format: date-time
        preferred_end_at:
          type: [string, 'null']
          format: date-time
        preferred_duration_ms:
          type: [integer, 'null']
        closure_mode:
          type: [string, 'null']
          enum: [observed, inferred, null]
        closure_reason:
          type: [string, 'null']
        observed_end_at:
          type: [string, 'null']
          format: date-time
        observed_closure_event_id:
          type: [string, 'null']
        source_disconnect_event_id:
          type: [string, 'null']
        inferred_end_at:
          type: [string, 'null']
          format: date-time
        inferred_closure_event_id:
          type: [string, 'null']
        last_heartbeat_at:
          type: [string, 'null']
          format: date-time
        lease_expires_at:
          type: [string, 'null']
          format: date-time
        reconciliation_status:
          type: string
          enum: [none, matched, changed]
        provisional:
          type: boolean
        state:
          type: string
          enum: [open, closed_observed, closed_inferred]
        definition_version:
          type: integer
        revision:
          type: integer
        as_of:
          type: string
          format: date-time
        retention_30d:
          $ref: '#/components/schemas/PlayerRetentionSummary'
        activity:
          $ref: '#/components/schemas/PlayerActivitySummary'
        lifecycle:
          $ref: '#/components/schemas/PlayerLifecycleSummary'
    PlayerRetentionSummary:
      type: [object, 'null']
      additionalProperties: false
      required: [sessions_30d, active_days_30d, days_since_previous_session, community_retention_band, as_of]
      properties:
        sessions_30d:
          type: integer
        active_days_30d:
          type: integer
        days_since_previous_session:
          type: [integer, 'null']
        community_retention_band:
          type: [string, 'null']
          enum: [above_typical, typical, below_typical, null]
        as_of:
          type: string
          format: date-time
    PlayerActivitySummary:
      type: object
      additionalProperties: false
      required: [death_count, chat_message_count, as_of]
      properties:
        death_count:
          type: [integer, 'null']
        chat_message_count:
          type: [integer, 'null']
        as_of:
          type: [string, 'null']
          format: date-time
    PlayerLifecycleSummary:
      type: object
      additionalProperties: false
      required: [spawn_count, completed_life_count, observed_death_count, unresolved_life_count, observed_survival_ms, longest_life_duration_ms, active_life, as_of]
      properties:
        spawn_count:
          type: integer
        completed_life_count:
          type: integer
        observed_death_count:
          type: integer
        unresolved_life_count:
          type: integer
        observed_survival_ms:
          type: integer
        longest_life_duration_ms:
          type: [integer, 'null']
        active_life:
          $ref: '#/components/schemas/ActiveLife'
        as_of:
          type: string
          format: date-time
    ActiveLife:
      type: [object, 'null']
      additionalProperties: false
      required: [spawn_session_id, spawned_at, state, reconciliation_status]
      properties:
        spawn_session_id:
          type: string
        spawned_at:
          type: [string, 'null']
          format: date-time
        state:
          type: string
          enum: [active, died_observed, ended_without_observed_death, death_observed_without_spawn]
        reconciliation_status:
          type: string
          enum: [none, pending, conflict, resolved]
    ServerInstanceStatus:
      type: object
      additionalProperties: false
      required: [server_instance_id, server_id, state, late_recovery_detected, last_heartbeat_at, suspect_at, lease_expires_at, inferred_at, open_session_count, inferred_session_count, operations, as_of, maintenance]
      properties:
        server_instance_id:
          type: string
        server_id:
          type: string
        state:
          type: string
          enum: [online, heartbeat_delayed, offline_inferred]
        late_recovery_detected:
          type: boolean
        last_heartbeat_at:
          type: [string, 'null']
          format: date-time
        suspect_at:
          type: [string, 'null']
          format: date-time
        lease_expires_at:
          type: [string, 'null']
          format: date-time
        inferred_at:
          type: [string, 'null']
          format: date-time
        open_session_count:
          type: integer
        inferred_session_count:
          type: integer
        operations:
          type: array
          items:
            $ref: '#/components/schemas/ServerOperation'
        as_of:
          type: string
          format: date-time
        maintenance:
          $ref: '#/components/schemas/MaintenanceState'
    ServerOperation:
      type: object
      additionalProperties: false
      required: [operation_event_id, event_type, schema_version, sequence, sequence_domain, source_adapter, source_adapter_version, source_event_id, occurred_at, recorded_at, reason, last_heartbeat_at, lease_expires_at, inferred_at, late_recovery_detected_at]
      properties:
        operation_event_id:
          type: string
        event_type:
          type: string
          enum: [server.started, server.stopped]
        schema_version:
          type: integer
        sequence:
          type: integer
        sequence_domain:
          type: string
          enum: [source, cloud]
        source_adapter:
          type: string
        source_adapter_version:
          type: string
        source_event_id:
          type: [string, 'null']
        occurred_at:
          type: string
          format: date-time
        recorded_at:
          type: string
          format: date-time
        reason:
          type: [string, 'null']
          enum: [graceful_shutdown, restart, unknown, heartbeat_timeout, null]
        last_heartbeat_at:
          type: [string, 'null']
          format: date-time
        lease_expires_at:
          type: [string, 'null']
          format: date-time
        inferred_at:
          type: [string, 'null']
          format: date-time
        late_recovery_detected_at:
          type: [string, 'null']
          format: date-time
    DetectionEventTypesResponse:
      type: object
      additionalProperties: false
      required: [event_types]
      properties:
        event_types:
          type: array
          items:
            type: string
    DetectionFieldsResponse:
      type: object
      additionalProperties: false
      required: [fields]
      properties:
        fields:
          type: array
          items:
            $ref: '#/components/schemas/DetectionField'
    DetectionField:
      type: object
      additionalProperties: false
      required: [field_id, label, type, operators]
      properties:
        field_id:
          type: string
        label:
          type: string
        type:
          type: string
          enum: [string, integer, number, boolean, ulid]
        operators:
          type: array
          items:
            type: string
            enum: [eq, neq, in, gt, gte, lt, lte]
    DetectionRuleListResponse:
      type: array
      items:
        $ref: '#/components/schemas/DetectionRuleSummary'
    DetectionRuleSummary:
      type: object
      additionalProperties: true
      required: [rule_id, name, description, severity, state, current_revision, template_kind, scope_summary]
      properties:
        rule_id:
          type: string
        name:
          type: string
        description:
          type: string
        severity:
          type: string
          enum: [info, low, medium, high, critical]
        state:
          type: string
          enum: [disabled, enabled, archived]
        current_revision:
          type: integer
        template_kind:
          type: string
          enum: [event_match, event_count, distinct_value_count, event_absence]
        scope_summary:
          type: string
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
        archived_at:
          type: [string, 'null']
          format: date-time
    DetectionRule:
      allOf:
        - $ref: '#/components/schemas/DetectionRuleSummary'
        - type: object
          additionalProperties: true
          properties:
            event_type:
              type: [string, 'null']
            schema_versions:
              type: array
              items:
                type: integer
            configuration:
              type: object
              additionalProperties: true
            configuration_sha256:
              type: [string, 'null']
            extractor_version:
              type: [string, 'null']
            revision_created_by:
              type: [string, 'null']
            revision_created_at:
              type: [string, 'null']
              format: date-time
    DetectionRuleWrite:
      type: object
      additionalProperties: true
      required: [name, severity]
      properties:
        name:
          type: string
          minLength: 1
        description:
          type: string
        severity:
          type: string
          enum: [info, low, medium, high, critical]
        configuration:
          type: object
          additionalProperties: true
        template_kind:
          type: string
          enum: [event_match, event_count, distinct_value_count, event_absence]
        event_type:
          type: string
        schema_versions:
          type: array
          items:
            type: integer
    DetectionRuleMutationResponse:
      type: object
      additionalProperties: false
      required: [rule_id, revision, state]
      properties:
        rule_id:
          type: string
        revision:
          type: integer
        state:
          type: string
          enum: [disabled, enabled, archived]
    DetectionRuleEnvelope:
      type: object
      additionalProperties: false
      required: [rule]
      properties:
        rule:
          $ref: '#/components/schemas/DetectionRule'
    DetectionOccurrenceListResponse:
      type: array
      items:
        $ref: '#/components/schemas/DetectionOccurrenceSummary'
    DetectionOccurrenceSummary:
      type: object
      additionalProperties: true
      required: [occurrence_id, rule_id, opening_revision, template_kind, severity, scope_key, state, opened_at, last_evidence_at, source_event_ids, evidence]
      properties:
        occurrence_id:
          type: string
        rule_id:
          type: string
        opening_revision:
          type: integer
        template_kind:
          type: string
          enum: [event_match, event_count, distinct_value_count, event_absence]
        severity:
          type: string
          enum: [info, low, medium, high, critical]
        scope_key:
          type: string
        server_id:
          type: [string, 'null']
        server_instance_id:
          type: [string, 'null']
        state:
          type: string
          enum: [open, resolved]
        opened_at:
          type: string
          format: date-time
        last_evidence_at:
          type: string
          format: date-time
        resolved_at:
          type: [string, 'null']
          format: date-time
        resolution_reason:
          type: [string, 'null']
          enum: [recovered, disarmed, quiet_window, disabled, archived, point_in_time, null]
        source_event_ids:
          type: array
          items:
            type: string
        evidence:
          type: object
          additionalProperties: true
    DetectionOccurrenceDetail:
      allOf:
        - $ref: '#/components/schemas/DetectionOccurrenceSummary'
        - type: object
          required: [transitions]
          properties:
            transitions:
              type: array
              items:
                $ref: '#/components/schemas/DetectionOccurrenceTransition'
    DetectionOccurrenceTransition:
      type: object
      additionalProperties: true
      required: [occurrence_event_id, transition_kind, occurred_at, source_event_ids, evidence]
      properties:
        occurrence_event_id:
          type: string
        transition_kind:
          type: string
          enum: [opened, evidence_updated, resolved]
        occurred_at:
          type: string
          format: date-time
        source_event_ids:
          type: array
          items:
            type: string
        evidence:
          type: object
          additionalProperties: true
    DetectionAlertListResponse:
      type: array
      items:
        $ref: '#/components/schemas/DetectionAlert'
    DetectionAlert:
      type: object
      additionalProperties: true
      required: [alert_id, rule_id, revision, template_kind, severity, scope_key, created_at]
      properties:
        alert_id:
          type: string
        rule_id:
          type: string
        revision:
          type: integer
        template_kind:
          type: string
          enum: [event_match, event_count, distinct_value_count, event_absence]
        severity:
          type: string
          enum: [info, low, medium, high, critical]
        scope_key:
          type: string
        server_id:
          type: [string, 'null']
        server_instance_id:
          type: [string, 'null']
        window_start:
          type: [string, 'null']
          format: date-time
        scheduled_deadline:
          type: [string, 'null']
          format: date-time
        trigger_count:
          type: [integer, 'null']
        source_event_ids:
          type: array
          items:
            type: string
        evidence:
          type: object
          additionalProperties: true
        created_at:
          type: string
          format: date-time
    ServerUptimePresetResponse:
      type: object
      additionalProperties: false
      required: [community_id, rules]
      properties:
        community_id:
          type: string
        rules:
          type: array
          items:
            $ref: '#/components/schemas/DetectionRulePreset'
    DetectionRulePreset:
      type: object
      additionalProperties: true
      required: [preset_key, name, description, severity, template_kind, configuration]
      properties:
        preset_key:
          type: string
        name:
          type: string
        description:
          type: string
        severity:
          type: string
          enum: [info, low, medium, high, critical]
        template_kind:
          type: string
          enum: [event_match, event_count, distinct_value_count, event_absence]
        configuration:
          type: object
          additionalProperties: true
    NotificationEndpoint:
      type: object
      additionalProperties: true
      required: [endpoint_id, display_name, state, destination_kind]
      properties:
        endpoint_id:
          type: string
        community_id:
          type: string
        display_name:
          type: string
        destination_kind:
          type: string
          enum: [discord, generic_webhook]
        state:
          type: string
          enum: [disabled, enabled, archived]
        health_state:
          type: [string, 'null']
          enum: [unknown, healthy, unhealthy, null]
        current_revision:
          type: integer
        current_secret_version:
          type: [integer, 'null']
        rule_ids:
          type: array
          items:
            type: string
        minimum_severity:
          type: string
          enum: [info, low, medium, high, critical]
        subscriptions_enabled:
          type: boolean
        created_by:
          type: string
        updated_by:
          type: string
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
        archived_at:
          type: [string, 'null']
          format: date-time
    DiscordEndpointCreateRequest:
      type: object
      additionalProperties: false
      required: [displayName, url]
      properties:
        displayName:
          type: string
          minLength: 1
        url:
          type: string
          format: uri
    DiscordEndpointCreateResponse:
      type: object
      additionalProperties: false
      required: [endpoint_id, display_name, destination_kind, state, health_state, revision, updated_at]
      properties:
        endpoint_id:
          type: string
        display_name:
          type: string
        destination_kind:
          const: discord
        state:
          type: string
          const: disabled
        health_state:
          type: string
          const: unknown
        revision:
          type: integer
        updated_at:
          type: string
          format: date-time
    GenericWebhookWrite:
      type: object
      additionalProperties: false
      required: [displayName, url, ruleIds, minimumSeverity, subscriptionsEnabled]
      properties:
        displayName:
          type: string
          minLength: 1
        url:
          type: string
          format: uri
        ruleIds:
          type: array
          minItems: 1
          maxItems: 100
          items:
            type: string
        minimumSeverity:
          type: string
          enum: [info, low, medium, high, critical]
        subscriptionsEnabled:
          type: boolean
    GenericWebhookCreateResponse:
      type: object
      additionalProperties: false
      required: [endpoint_id, secret]
      properties:
        endpoint_id:
          type: string
        secret:
          type: string
    NotificationStateResponse:
      type: object
      additionalProperties: false
      required: [endpoint_id, state]
      properties:
        endpoint_id:
          type: string
        state:
          type: string
          enum: [disabled, enabled, archived]
    NotificationRevisionResponse:
      type: object
      additionalProperties: false
      required: [endpoint_id, revision]
      properties:
        endpoint_id:
          type: string
        revision:
          type: integer
    NotificationSecretResponse:
      type: object
      additionalProperties: false
      required: [endpoint_id, secret, version]
      properties:
        endpoint_id:
          type: string
        secret:
          type: string
        version:
          type: integer
    NotificationDeliveriesResponse:
      type: object
      additionalProperties: false
      required: [deliveries]
      properties:
        deliveries:
          type: array
          items:
            $ref: '#/components/schemas/NotificationDelivery'
    NotificationDelivery:
      type: object
      additionalProperties: true
      required: [delivery_id, alert_id, endpoint_id, endpoint_revision, secret_version, rule_id, severity, payload_version, state, created_at, available_at, retry_deadline, attempt_count]
      properties:
        delivery_id:
          type: string
        alert_id:
          type: string
        endpoint_id:
          type: string
        endpoint_revision:
          type: integer
        secret_version:
          type: integer
        rule_id:
          type: string
        severity:
          type: string
          enum: [info, low, medium, high, critical]
        url_snapshot:
          type: [string, 'null']
          format: uri
        payload_version:
          type: integer
        state:
          type: string
          enum: [pending, leased, succeeded, failed]
        created_at:
          type: string
          format: date-time
        available_at:
          type: string
          format: date-time
        retry_deadline:
          type: string
          format: date-time
        attempt_count:
          type: integer
        lease_token:
          type: [string, 'null']
        lease_expires_at:
          type: [string, 'null']
          format: date-time
        terminal_at:
          type: [string, 'null']
          format: date-time
        last_outcome_code:
          type: [string, 'null']
    ReplayResponse:
      type: object
      additionalProperties: false
      required: [replay_id]
      properties:
        replay_id:
          type: string
    MaintenanceWindow:
      type: object
      additionalProperties: false
      required: [window_id, community_id, scope, target_id, server_instance_id, reason, starts_at, ends_at, status, created_by, created_at, updated_by, updated_at, stopped_at, expired_at]
      properties:
        window_id:
          type: string
        community_id:
          type: string
        scope:
          type: string
          enum: [community, server_instance]
        target_id:
          type: string
        server_instance_id:
          type: [string, 'null']
        reason:
          type: string
        starts_at:
          type: string
          format: date-time
        ends_at:
          type: [string, 'null']
          format: date-time
        status:
          type: string
          enum: [scheduled, active, stopped, expired]
        created_by:
          type: string
        created_at:
          type: string
          format: date-time
        updated_by:
          type: string
        updated_at:
          type: string
          format: date-time
        stopped_at:
          type: [string, 'null']
          format: date-time
        expired_at:
          type: [string, 'null']
          format: date-time
    MaintenanceWindowCreate:
      type: object
      additionalProperties: false
      required: [reason]
      properties:
        reason:
          type: string
          minLength: 1
          maxLength: 512
        starts_at:
          type: string
          format: date-time
        ends_at:
          type: [string, 'null']
          format: date-time
    MaintenanceWindowUpdate:
      type: object
      additionalProperties: false
      required: [ends_at]
      properties:
        reason:
          type: string
          maxLength: 512
        ends_at:
          type: string
          format: date-time
    MaintenanceState:
      type: object
      additionalProperties: true
      required: [state]
      properties:
        state:
          type: string
          enum: [none, community, server_instance]
        communityWindow:
          type: [object, 'null']
          additionalProperties: true
        serverInstanceWindow:
          type: [object, 'null']
          additionalProperties: true
        activeWindows:
          type: array
          items:
            $ref: '#/components/schemas/MaintenanceWindow'
    CommunityMaintenanceResponse:
      type: object
      additionalProperties: false
      required: [maintenance, windows]
      properties:
        maintenance:
          $ref: '#/components/schemas/MaintenanceState'
        windows:
          type: array
          items:
            $ref: '#/components/schemas/MaintenanceWindow'
    ServerMaintenanceResponse:
      type: object
      additionalProperties: false
      required: [maintenance, windows]
      properties:
        maintenance:
          $ref: '#/components/schemas/MaintenanceState'
        windows:
          type: array
          items:
            $ref: '#/components/schemas/MaintenanceWindow'
