openapi: 3.1.0
info:
  title: LatidoFlow API
  version: 1.0.0
  summary: Language-neutral monitoring ingestion and customer-authorized management.
  description: |
    LatidoFlow exposes two deliberately separate authentication planes.

    Runtime applications send monitor definitions and execution evidence with a
    workspace- or monitor-scoped ingestion token. Customer-authorized management
    clients use OAuth 2.1 with the `mcp:use` scope. The two bearer-token types are
    not interchangeable.

    Every tenant-scoped management path contains an explicit workspace UUID.
    Management responses are allowlisted and omit credentials, endpoint URLs,
    idempotency keys, queue connection details, logs, free-form metadata, raw
    incident context, and internal failure payloads. Runtime evidence is accepted
    only by the ingestion operations; management and MCP operations cannot create,
    complete, fail, or fabricate a run.
  contact:
    name: LatidoFlow
    url: https://www.latidoflow.com/docs
servers:
  - url: https://www.latidoflow.com
    description: Canonical hosted origin.
tags:
  - name: Ingestion definitions
    description: Synchronize heartbeat or uptime definitions with a workspace ingestion token.
  - name: Ingestion lifecycle
    description: Write queued, running, skipped, progress, terminal, and log evidence.
  - name: Management workspaces
    description: Discover an OAuth user's accessible workspaces and redacted workspace state.
  - name: Management inventory
    description: Read workspace projects, environments, monitor definitions, and run summaries.
  - name: Management incidents
    description: Read or explicitly confirm policy-authorized incident responses.
paths:
  /api/v1/monitors/sync:
    post:
      operationId: syncIngestionMonitorDefinitions
      tags: [Ingestion definitions]
      summary: Synchronize monitor definitions with an ingestion credential
      description: |
        Requires a workspace-scoped ingestion token with `monitors:sync`. The
        operation creates or updates heartbeat and uptime definitions but does
        not constitute runtime execution evidence.
      security:
        - IngestionBearer: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MonitorDefinitionSyncRequest'
      responses:
        '200':
          description: Definitions were synchronized.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IngestionMonitorSyncResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/ValidationError'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v1/runtime/runs/queued:
    post:
      operationId: queueReferencedRun
      tags: [Ingestion lifecycle]
      summary: Record a queued run by stable slugs
      description: |
        Requires a workspace-scoped ingestion token with `runs:write`. Supply a
        stable idempotency key through the `Idempotency-Key` header, the JSON body,
        or the `key` query parameter. Reusing that key returns the existing run.
      security:
        - IngestionBearer: []
      parameters:
        - $ref: '#/components/parameters/IdempotencyKeyHeader'
        - $ref: '#/components/parameters/IdempotencyKeyQuery'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReferencedRunEventRequest'
      responses:
        '200':
          description: An idempotent replay returned the existing run.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DeduplicatedRunLifecycleResponse'
        '201':
          description: A queued run was created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DeduplicatedRunLifecycleResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '422':
          $ref: '#/components/responses/ValidationError'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v1/runtime/runs/start:
    post:
      operationId: startReferencedRun
      tags: [Ingestion lifecycle]
      summary: Start a run by stable slugs
      description: |
        Requires a workspace-scoped ingestion token with `runs:write`. A queued
        run can be promoted to running with the same stable idempotency key.
        One idempotency-key source is required.
      security:
        - IngestionBearer: []
      parameters:
        - $ref: '#/components/parameters/IdempotencyKeyHeader'
        - $ref: '#/components/parameters/IdempotencyKeyQuery'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReferencedRunEventRequest'
      responses:
        '200':
          description: An existing logical run was returned or started.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RunLifecycleResponse'
        '201':
          description: A running run was created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RunLifecycleResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '422':
          $ref: '#/components/responses/ValidationError'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v1/runtime/runs/skipped:
    post:
      operationId: skipReferencedRun
      tags: [Ingestion lifecycle]
      summary: Record an intentionally skipped occurrence by stable slugs
      description: |
        Requires a workspace-scoped ingestion token with `runs:write`. The stable
        idempotency key prevents a replay from advancing the schedule twice. A
        skip updates the expected window without creating a successful run.
      security:
        - IngestionBearer: []
      parameters:
        - $ref: '#/components/parameters/IdempotencyKeyHeader'
        - $ref: '#/components/parameters/IdempotencyKeyQuery'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReferencedRunEventRequest'
      responses:
        '200':
          description: The skipped occurrence was recorded or replayed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SkippedRunResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '422':
          $ref: '#/components/responses/ValidationError'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v1/monitors/{monitorUuid}/runs/start:
    post:
      operationId: startMonitorRun
      tags: [Ingestion lifecycle]
      summary: Start a run for a known monitor UUID
      description: |
        Requires `runs:write` on a workspace- or monitor-scoped ingestion token.
        Idempotency is optional for this operation but recommended.
      security:
        - IngestionBearer: []
      parameters:
        - $ref: '#/components/parameters/MonitorUuid'
        - $ref: '#/components/parameters/IdempotencyKeyHeader'
        - $ref: '#/components/parameters/IdempotencyKeyQuery'
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RunEventRequest'
      responses:
        '200':
          description: An idempotent replay returned the existing run.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DeduplicatedRunLifecycleResponse'
        '201':
          description: A running run was created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DeduplicatedRunLifecycleResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '422':
          $ref: '#/components/responses/ValidationError'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v1/runs/{runUuid}/heartbeat:
    post:
      operationId: heartbeatRun
      tags: [Ingestion lifecycle]
      summary: Refresh progress for a running run
      description: Requires `runs:write`. A queued run must be started before it can report progress.
      security:
        - IngestionBearer: []
      parameters:
        - $ref: '#/components/parameters/RunUuid'
        - $ref: '#/components/parameters/IdempotencyKeyHeader'
        - $ref: '#/components/parameters/IdempotencyKeyQuery'
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RunEventRequest'
      responses:
        '200':
          description: Progress was accepted or an already terminal run was returned unchanged.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RunLifecycleResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '422':
          $ref: '#/components/responses/ValidationError'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v1/runs/{runUuid}/success:
    post:
      operationId: succeedRun
      tags: [Ingestion lifecycle]
      summary: Finish a run with business-outcome evidence
      description: |
        Requires `runs:write`. Numeric output and bounded structured evidence are
        evaluated against the run's snapshotted contract. A failed assertion can
        make the stored terminal state failed even though this endpoint accepted
        the completion request.
      security:
        - IngestionBearer: []
      parameters:
        - $ref: '#/components/parameters/RunUuid'
        - $ref: '#/components/parameters/IdempotencyKeyHeader'
        - $ref: '#/components/parameters/IdempotencyKeyQuery'
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RunSuccessRequest'
      responses:
        '200':
          description: The terminal transition was accepted or replayed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RunLifecycleResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '422':
          $ref: '#/components/responses/ValidationError'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v1/runs/{runUuid}/fail:
    post:
      operationId: failRun
      tags: [Ingestion lifecycle]
      summary: Finish a run as failed
      description: Requires `runs:write`. Send a bounded, sanitized failure summary; do not submit secrets or raw payloads.
      security:
        - IngestionBearer: []
      parameters:
        - $ref: '#/components/parameters/RunUuid'
        - $ref: '#/components/parameters/IdempotencyKeyHeader'
        - $ref: '#/components/parameters/IdempotencyKeyQuery'
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RunEventRequest'
      responses:
        '200':
          description: The terminal transition was accepted or replayed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RunLifecycleResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '422':
          $ref: '#/components/responses/ValidationError'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v1/runs/{runUuid}/logs:
    post:
      operationId: appendRunLogs
      tags: [Ingestion lifecycle]
      summary: Append one log or a batch of logs
      description: Requires `logs:write`. A batch contains at most 32 records. Messages are bounded and have embedded URL credentials and sensitive URL query values redacted on persistence; structured context is bounded and secret-key redacted.
      security:
        - IngestionBearer: []
      parameters:
        - $ref: '#/components/parameters/RunUuid'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RunLogRequest'
      responses:
        '200':
          description: The logs were stored.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StoredLogsResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/ValidationError'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v1/workspaces:
    get:
      operationId: listWorkspaces
      tags: [Management workspaces]
      summary: List accessible workspaces
      description: Returns workspaces owned by the OAuth user or joined through an accepted membership.
      security:
        - ManagementOAuth: [mcp:use]
      parameters:
        - $ref: '#/components/parameters/PerPage'
      responses:
        '200':
          description: A paginated, redacted workspace collection.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaginatedWorkspaces'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          $ref: '#/components/responses/ValidationError'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v1/workspaces/{workspaceUuid}:
    get:
      operationId: getWorkspace
      tags: [Management workspaces]
      summary: Get one accessible workspace
      security:
        - ManagementOAuth: [mcp:use]
      parameters:
        - $ref: '#/components/parameters/WorkspaceUuid'
      responses:
        '200':
          description: The redacted workspace.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkspaceResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v1/workspaces/{workspaceUuid}/overview:
    get:
      operationId: getWorkspaceOverview
      tags: [Management workspaces]
      summary: Get redacted inventory and integration-evidence counts
      security:
        - ManagementOAuth: [mcp:use]
      parameters:
        - $ref: '#/components/parameters/WorkspaceUuid'
      responses:
        '200':
          description: Workspace, inventory counts, and activation milestones.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkspaceOverviewResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v1/workspaces/{workspaceUuid}/projects:
    get:
      operationId: listWorkspaceProjects
      tags: [Management inventory]
      summary: List projects in a workspace
      security:
        - ManagementOAuth: [mcp:use]
      parameters:
        - $ref: '#/components/parameters/WorkspaceUuid'
        - $ref: '#/components/parameters/PerPage'
      responses:
        '200':
          description: A paginated project collection.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaginatedProjects'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/ValidationError'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v1/workspaces/{workspaceUuid}/projects/{projectUuid}:
    get:
      operationId: getWorkspaceProject
      tags: [Management inventory]
      summary: Get one workspace project
      security:
        - ManagementOAuth: [mcp:use]
      parameters:
        - $ref: '#/components/parameters/WorkspaceUuid'
        - $ref: '#/components/parameters/ProjectUuid'
      responses:
        '200':
          description: The project.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProjectResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v1/workspaces/{workspaceUuid}/environments:
    get:
      operationId: listWorkspaceEnvironments
      tags: [Management inventory]
      summary: List environments in a workspace
      security:
        - ManagementOAuth: [mcp:use]
      parameters:
        - $ref: '#/components/parameters/WorkspaceUuid'
        - $ref: '#/components/parameters/PerPage'
      responses:
        '200':
          description: A paginated environment collection.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaginatedEnvironments'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/ValidationError'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v1/workspaces/{workspaceUuid}/environments/{environmentUuid}:
    get:
      operationId: getWorkspaceEnvironment
      tags: [Management inventory]
      summary: Get one workspace environment
      security:
        - ManagementOAuth: [mcp:use]
      parameters:
        - $ref: '#/components/parameters/WorkspaceUuid'
        - $ref: '#/components/parameters/EnvironmentUuid'
      responses:
        '200':
          description: The environment.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EnvironmentResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v1/workspaces/{workspaceUuid}/monitors/sync:
    post:
      operationId: syncManagementMonitorDefinitions
      tags: [Management inventory]
      summary: Synchronize definitions as an authorized customer
      description: |
        Creates or updates heartbeat and uptime definitions after workspace-policy
        authorization. Unlike the ingestion route, this operation uses customer
        OAuth and never accepts an ingestion credential. Definition sync is
        configuration, not runtime evidence.
      security:
        - ManagementOAuth: [mcp:use]
      parameters:
        - $ref: '#/components/parameters/WorkspaceUuid'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MonitorDefinitionSyncRequest'
      responses:
        '200':
          description: Definitions were synchronized and returned through allowlisted resources.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ManagementMonitorSyncResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/ValidationError'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v1/workspaces/{workspaceUuid}/monitors:
    get:
      operationId: listWorkspaceMonitors
      tags: [Management inventory]
      summary: List redacted monitor definitions and state
      security:
        - ManagementOAuth: [mcp:use]
      parameters:
        - $ref: '#/components/parameters/WorkspaceUuid'
        - $ref: '#/components/parameters/PerPage'
      responses:
        '200':
          description: A paginated, allowlisted monitor collection.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaginatedMonitors'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/ValidationError'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v1/workspaces/{workspaceUuid}/monitors/{monitorUuid}:
    get:
      operationId: getWorkspaceMonitor
      tags: [Management inventory]
      summary: Get one redacted monitor
      security:
        - ManagementOAuth: [mcp:use]
      parameters:
        - $ref: '#/components/parameters/WorkspaceUuid'
        - $ref: '#/components/parameters/MonitorUuid'
      responses:
        '200':
          description: The allowlisted monitor definition and state.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MonitorResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v1/workspaces/{workspaceUuid}/runs:
    get:
      operationId: listWorkspaceRuns
      tags: [Management inventory]
      summary: List redacted run summaries
      security:
        - ManagementOAuth: [mcp:use]
      parameters:
        - $ref: '#/components/parameters/WorkspaceUuid'
        - $ref: '#/components/parameters/PerPage'
      responses:
        '200':
          description: A paginated, allowlisted run collection.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaginatedRuns'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/ValidationError'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v1/workspaces/{workspaceUuid}/runs/{runUuid}:
    get:
      operationId: getWorkspaceRun
      tags: [Management inventory]
      summary: Get one redacted run summary
      security:
        - ManagementOAuth: [mcp:use]
      parameters:
        - $ref: '#/components/parameters/WorkspaceUuid'
        - $ref: '#/components/parameters/RunUuid'
      responses:
        '200':
          description: The allowlisted run summary.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MonitorRunResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v1/workspaces/{workspaceUuid}/incidents:
    get:
      operationId: listWorkspaceIncidents
      tags: [Management incidents]
      summary: List redacted incidents
      security:
        - ManagementOAuth: [mcp:use]
      parameters:
        - $ref: '#/components/parameters/WorkspaceUuid'
        - $ref: '#/components/parameters/PerPage'
      responses:
        '200':
          description: A paginated, allowlisted incident collection.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaginatedIncidents'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/ValidationError'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v1/workspaces/{workspaceUuid}/incidents/{incidentUuid}:
    get:
      operationId: getWorkspaceIncident
      tags: [Management incidents]
      summary: Get one redacted incident
      security:
        - ManagementOAuth: [mcp:use]
      parameters:
        - $ref: '#/components/parameters/WorkspaceUuid'
        - $ref: '#/components/parameters/IncidentUuid'
      responses:
        '200':
          description: The allowlisted incident.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IncidentResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v1/workspaces/{workspaceUuid}/incidents/{incidentUuid}/acknowledge:
    post:
      operationId: acknowledgeWorkspaceIncident
      tags: [Management incidents]
      summary: Acknowledge an incident after explicit confirmation
      description: "Requires incident-response policy access, an operator reason, and `confirmed: true`. The action is audited."
      security:
        - ManagementOAuth: [mcp:use]
      parameters:
        - $ref: '#/components/parameters/WorkspaceUuid'
        - $ref: '#/components/parameters/IncidentUuid'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ConfirmedIncidentReasonRequest'
      responses:
        '200':
          description: The incident was returned with whether state changed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IncidentMutationResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/ValidationError'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v1/workspaces/{workspaceUuid}/incidents/{incidentUuid}/silence:
    post:
      operationId: silenceWorkspaceIncident
      tags: [Management incidents]
      summary: Silence an incident for a bounded period after explicit confirmation
      description: "Requires incident-response policy access, an operator reason, and `confirmed: true`. The action is audited."
      security:
        - ManagementOAuth: [mcp:use]
      parameters:
        - $ref: '#/components/parameters/WorkspaceUuid'
        - $ref: '#/components/parameters/IncidentUuid'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ConfirmedIncidentSilenceRequest'
      responses:
        '200':
          description: The incident was returned with whether state changed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IncidentMutationResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/ValidationError'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v1/workspaces/{workspaceUuid}/incidents/{incidentUuid}/unsilence:
    post:
      operationId: unsilenceWorkspaceIncident
      tags: [Management incidents]
      summary: Remove an incident silence after explicit confirmation
      description: "Requires incident-response policy access, an operator reason, and `confirmed: true`. The action is audited."
      security:
        - ManagementOAuth: [mcp:use]
      parameters:
        - $ref: '#/components/parameters/WorkspaceUuid'
        - $ref: '#/components/parameters/IncidentUuid'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ConfirmedIncidentReasonRequest'
      responses:
        '200':
          description: The incident was returned with whether state changed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IncidentMutationResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/ValidationError'
        '429':
          $ref: '#/components/responses/RateLimited'

components:
  securitySchemes:
    IngestionBearer:
      type: http
      scheme: bearer
      bearerFormat: LatidoFlow ingestion token
      description: |
        A hashed, reveal-once workspace- or monitor-scoped credential such as an
        `lf_live_...` token. Its abilities can include `monitors:sync`,
        `runs:write`, or `logs:write`. It is authenticated before payload
        validation, and monitor/run lookup is constrained to its scope. Never
        send this credential to management REST or MCP.
    ManagementOAuth:
      type: oauth2
      description: |
        Customer OAuth 2.1 authorization with PKCE. The authenticated user must
        have a verified email and the required workspace policy access. Never
        embed this access token in a monitored runtime.
      flows:
        authorizationCode:
          authorizationUrl: https://www.latidoflow.com/oauth/authorize
          tokenUrl: https://www.latidoflow.com/oauth/token
          refreshUrl: https://www.latidoflow.com/oauth/token
          scopes:
            mcp:use: Read and perform policy-authorized LatidoFlow management operations.

  parameters:
    WorkspaceUuid:
      name: workspaceUuid
      in: path
      required: true
      description: Exact UUID of the workspace selected through an authorized list operation.
      schema:
        type: string
        format: uuid
    ProjectUuid:
      name: projectUuid
      in: path
      required: true
      schema:
        type: string
        format: uuid
    EnvironmentUuid:
      name: environmentUuid
      in: path
      required: true
      schema:
        type: string
        format: uuid
    MonitorUuid:
      name: monitorUuid
      in: path
      required: true
      schema:
        type: string
        format: uuid
    RunUuid:
      name: runUuid
      in: path
      required: true
      schema:
        type: string
        format: uuid
    IncidentUuid:
      name: incidentUuid
      in: path
      required: true
      schema:
        type: string
        format: uuid
    PerPage:
      name: per_page
      in: query
      required: false
      description: Number of records per page.
      schema:
        type: integer
        minimum: 1
        maximum: 100
        default: 25
    IdempotencyKeyHeader:
      name: Idempotency-Key
      in: header
      required: false
      description: Stable key for the same logical event. Reuse it when retrying an uncertain delivery.
      schema:
        type: string
        minLength: 1
        maxLength: 128
        pattern: '^[A-Za-z0-9._:-]+$'
    IdempotencyKeyQuery:
      name: key
      in: query
      required: false
      description: Compatibility location for the idempotency key; prefer the header.
      schema:
        type: string
        minLength: 1
        maxLength: 128
        pattern: '^[A-Za-z0-9._:-]+$'

  responses:
    Unauthorized:
      description: The bearer credential is missing, invalid, expired, revoked, or of the wrong authentication type.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Problem'
    Forbidden:
      description: The OAuth scope, verified-user requirement, or workspace policy denied the operation.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Problem'
    NotFound:
      description: The resource does not exist within the credential's authorized workspace scope.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Problem'
    Conflict:
      description: The requested lifecycle transition conflicts with the current monitor or run state.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Problem'
    ValidationError:
      description: The request failed validation. Confirmation-sensitive management actions also return this response when `confirmed` is absent or false.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ValidationProblem'
    RateLimited:
      description: The credential, OAuth flow, or source IP exceeded its configured rate limit.
      headers:
        Retry-After:
          description: Seconds to wait before retrying, when supplied.
          schema:
            type: integer
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Problem'

  schemas:
    Problem:
      type: object
      properties:
        message:
          type: string
      required: [message]
      additionalProperties: true
    ValidationProblem:
      type: object
      properties:
        message:
          type: string
        errors:
          type: object
          additionalProperties:
            type: array
            items:
              type: string
      required: [message, errors]
      additionalProperties: false

    MonitorDefinitionSyncRequest:
      type: object
      properties:
        project:
          oneOf:
            - $ref: '#/components/schemas/ProjectDefinition'
            - type: 'null'
        environment:
          oneOf:
            - $ref: '#/components/schemas/EnvironmentDefinition'
            - type: 'null'
        monitors:
          type: array
          minItems: 1
          maxItems: 100
          items:
            $ref: '#/components/schemas/MonitorDefinition'
      required: [monitors]
    ProjectDefinition:
      type: object
      properties:
        name:
          type: [string, 'null']
          maxLength: 120
        slug:
          type: [string, 'null']
          maxLength: 120
      additionalProperties: false
    EnvironmentDefinition:
      type: object
      properties:
        name:
          type: [string, 'null']
          maxLength: 120
        slug:
          type: [string, 'null']
          maxLength: 120
        kind:
          type: [string, 'null']
          maxLength: 60
        is_production:
          type: [boolean, 'null']
      additionalProperties: false
    MonitorDefinition:
      type: object
      properties:
        name:
          type: string
          maxLength: 160
        slug:
          type: [string, 'null']
          maxLength: 160
        type:
          type: string
          enum: [heartbeat, uptime]
        description:
          type: [string, 'null']
          maxLength: 1000
        cron_expression:
          type: [string, 'null']
          maxLength: 120
        timezone:
          type: [string, 'null']
          description: Valid IANA timezone.
        check_interval_minutes:
          type: [integer, 'null']
          minimum: 1
          maximum: 10080
        grace_seconds:
          type: [integer, 'null']
          minimum: 0
          maximum: 86400
        timeout_seconds:
          type: [integer, 'null']
          minimum: 1
          maximum: 604800
        expected_duration_seconds:
          type: [integer, 'null']
          minimum: 1
          maximum: 604800
        duplicate_window_seconds:
          type: [integer, 'null']
          minimum: 1
          maximum: 86400
        output_assertions:
          type: array
          maxItems: 10
          items:
            $ref: '#/components/schemas/OutputAssertion'
        semantic_checks:
          type: [object, 'null']
          description: Versioned, server-validated semantic-check contract; at most 20 rules.
        alert_truth:
          type: [object, 'null']
          description: Server-validated uptime confirmation policy.
        metadata:
          oneOf:
            - $ref: '#/components/schemas/BoundedObject'
            - type: 'null'
          description: Bounded configuration metadata. Secret-shaped values are redacted from persisted evidence and never returned by management resources.
        is_active:
          type: [boolean, 'null']
      required: [name, type]
      additionalProperties: false
    OutputAssertion:
      type: object
      properties:
        metric:
          type: string
          minLength: 1
          maxLength: 64
          pattern: '^[A-Za-z][A-Za-z0-9_.-]{0,63}$'
        operator:
          type: string
          enum: [gte, lte, equals]
        value:
          type: number
      required: [metric, operator, value]
      additionalProperties: false

    RunEventRequest:
      type: object
      properties:
        run_uuid:
          type: [string, 'null']
          format: uuid
        idempotency_key:
          type: [string, 'null']
          minLength: 1
          maxLength: 128
          pattern: '^[A-Za-z0-9._:-]+$'
        event_idempotency_key:
          type: [string, 'null']
          minLength: 1
          maxLength: 128
          pattern: '^[A-Za-z0-9._:-]+$'
        source:
          type: [string, 'null']
          maxLength: 60
          description: Caller-defined non-secret source label. Internal reserved source names are rejected.
        queue_connection:
          type: [string, 'null']
          maxLength: 80
        queue_name:
          type: [string, 'null']
          maxLength: 120
        metadata:
          oneOf:
            - $ref: '#/components/schemas/BoundedObject'
            - type: 'null'
        occurred_at:
          type: [string, 'null']
          format: date-time
        exit_code:
          type: [integer, 'null']
        message:
          type: [string, 'null']
          maxLength: 10000
        failure_message:
          type: [string, 'null']
          maxLength: 10000
    ReferencedRunEventRequest:
      allOf:
        - $ref: '#/components/schemas/RunEventRequest'
        - type: object
          properties:
            project_slug:
              type: string
              maxLength: 120
              pattern: '^[A-Za-z0-9_-]+$'
            environment_slug:
              type: string
              maxLength: 120
              pattern: '^[A-Za-z0-9_-]+$'
            monitor_slug:
              type: string
              maxLength: 160
              pattern: '^[A-Za-z0-9_-]+$'
            idempotency_key:
              type: [string, 'null']
              minLength: 1
              maxLength: 128
              pattern: '^[A-Za-z0-9._:-]+$'
          required: [project_slug, environment_slug, monitor_slug]
      description: One idempotency key source is also required; prefer the `Idempotency-Key` header.
    RunSuccessRequest:
      allOf:
        - $ref: '#/components/schemas/RunEventRequest'
        - type: object
          properties:
            output:
              $ref: '#/components/schemas/NumericOutput'
            evidence:
              oneOf:
                - type: object
                - type: array
              description: JSON-compatible structured evidence, encoded size at most 16 KiB and subject to server depth, node, key, and string limits.
    RunLogRequest:
      oneOf:
        - $ref: '#/components/schemas/SingleRunLog'
        - type: object
          properties:
            logs:
              type: array
              minItems: 1
              maxItems: 32
              items:
                $ref: '#/components/schemas/RunLogItem'
          required: [logs]
    SingleRunLog:
      allOf:
        - $ref: '#/components/schemas/RunLogItem'
        - type: object
          required: [message]
    RunLogItem:
      type: object
      properties:
        level:
          type: [string, 'null']
          maxLength: 20
        message:
          type: string
          maxLength: 10000
        context:
          oneOf:
            - $ref: '#/components/schemas/BoundedObject'
            - type: 'null'
        logged_at:
          type: [string, 'null']
          format: date-time
      additionalProperties: false
    BoundedObject:
      type: object
      description: JSON-compatible map, at most 8 KiB, 100 nodes, four nested levels, and 1,024 characters per key or string value.
      additionalProperties: true
    NumericOutput:
      type: object
      maxProperties: 20
      propertyNames:
        pattern: '^[A-Za-z][A-Za-z0-9_.-]{0,63}$'
      additionalProperties:
        type: number

    IngestionMonitorSyncResponse:
      type: object
      properties:
        project_uuid:
          type: string
          format: uuid
        environment_uuid:
          type: string
          format: uuid
        monitors:
          type: array
          items:
            type: object
            properties:
              uuid:
                type: string
                format: uuid
              slug:
                type: string
              type:
                type: string
                enum: [heartbeat, uptime]
              next_due_at:
                type: [string, 'null']
                format: date-time
            required: [uuid, slug, type, next_due_at]
            additionalProperties: false
      required: [project_uuid, environment_uuid, monitors]
      additionalProperties: false
    RunLifecycleResponse:
      type: object
      properties:
        run_uuid:
          type: string
          format: uuid
        monitor_uuid:
          type: string
          format: uuid
        status:
          type: string
        queued_at:
          type: [string, 'null']
          format: date-time
        started_at:
          type: [string, 'null']
          format: date-time
        finished_at:
          type: [string, 'null']
          format: date-time
        failure_message:
          type: [string, 'null']
        output_assertion_status:
          type: [string, 'null']
        semantic_check_status:
          type: [string, 'null']
      required:
        - run_uuid
        - monitor_uuid
        - status
        - queued_at
        - started_at
        - finished_at
        - failure_message
        - output_assertion_status
        - semantic_check_status
      additionalProperties: true
    DeduplicatedRunLifecycleResponse:
      allOf:
        - $ref: '#/components/schemas/RunLifecycleResponse'
        - type: object
          properties:
            deduplicated:
              type: boolean
          required: [deduplicated]
    SkippedRunResponse:
      type: object
      properties:
        monitor_uuid:
          type: string
          format: uuid
        status:
          type: string
          const: skipped
        skipped_at:
          type: [string, 'null']
          format: date-time
        next_due_at:
          type: [string, 'null']
          format: date-time
      required: [monitor_uuid, status, skipped_at, next_due_at]
      additionalProperties: false
    StoredLogsResponse:
      type: object
      properties:
        stored:
          type: integer
          minimum: 0
          maximum: 32
      required: [stored]
      additionalProperties: false

    Workspace:
      type: object
      properties:
        uuid:
          type: string
          format: uuid
        name:
          type: string
        slug:
          type: string
        timezone:
          type: string
        health_status:
          type: string
        onboarding_completed_at:
          type: [string, 'null']
          format: date-time
        created_at:
          type: [string, 'null']
          format: date-time
        updated_at:
          type: [string, 'null']
          format: date-time
      required: [uuid, name, slug, timezone, health_status, onboarding_completed_at, created_at, updated_at]
      additionalProperties: false
    Project:
      type: object
      properties:
        uuid:
          type: string
          format: uuid
        workspace_uuid:
          type: [string, 'null']
          format: uuid
        name:
          type: string
        slug:
          type: string
        archived_at:
          type: [string, 'null']
          format: date-time
        created_at:
          type: [string, 'null']
          format: date-time
        updated_at:
          type: [string, 'null']
          format: date-time
      required: [uuid, workspace_uuid, name, slug, archived_at, created_at, updated_at]
      additionalProperties: false
    Environment:
      type: object
      properties:
        uuid:
          type: string
          format: uuid
        workspace_uuid:
          type: [string, 'null']
          format: uuid
        project_uuid:
          type: [string, 'null']
          format: uuid
        name:
          type: string
        slug:
          type: string
        kind:
          type: string
        is_production:
          type: boolean
        created_at:
          type: [string, 'null']
          format: date-time
        updated_at:
          type: [string, 'null']
          format: date-time
      required: [uuid, workspace_uuid, project_uuid, name, slug, kind, is_production, created_at, updated_at]
      additionalProperties: false
    Monitor:
      type: object
      description: Allowlisted monitor data. Endpoint URLs, credentials, and metadata are intentionally absent.
      properties:
        uuid:
          type: string
          format: uuid
        workspace_uuid:
          type: [string, 'null']
          format: uuid
        project_uuid:
          type: [string, 'null']
          format: uuid
        environment_uuid:
          type: [string, 'null']
          format: uuid
        name:
          type: string
        slug:
          type: string
        type:
          type: string
          enum: [heartbeat, uptime]
        description:
          type: [string, 'null']
        cron_expression:
          type: [string, 'null']
        timezone:
          type: string
        check_interval_minutes:
          type: [integer, 'null']
        grace_seconds:
          type: integer
        timeout_seconds:
          type: integer
        expected_duration_seconds:
          type: [integer, 'null']
        duplicate_window_seconds:
          type: integer
        health_status:
          type: string
        is_active:
          type: boolean
        paused_at:
          type: [string, 'null']
          format: date-time
        next_due_at:
          type: [string, 'null']
          format: date-time
        last_started_at:
          type: [string, 'null']
          format: date-time
        last_finished_at:
          type: [string, 'null']
          format: date-time
        last_success_at:
          type: [string, 'null']
          format: date-time
        last_failure_at:
          type: [string, 'null']
          format: date-time
        last_heartbeat_at:
          type: [string, 'null']
          format: date-time
        last_event_classification:
          type: [string, 'null']
        created_at:
          type: [string, 'null']
          format: date-time
        updated_at:
          type: [string, 'null']
          format: date-time
      required:
        - uuid
        - workspace_uuid
        - project_uuid
        - environment_uuid
        - name
        - slug
        - type
        - description
        - cron_expression
        - timezone
        - check_interval_minutes
        - grace_seconds
        - timeout_seconds
        - expected_duration_seconds
        - duplicate_window_seconds
        - health_status
        - is_active
        - paused_at
        - next_due_at
        - last_started_at
        - last_finished_at
        - last_success_at
        - last_failure_at
        - last_heartbeat_at
        - last_event_classification
        - created_at
        - updated_at
      additionalProperties: false
    MonitorRun:
      type: object
      description: Allowlisted run data. Idempotency keys, queue details, metadata, logs, and failure messages are intentionally absent.
      properties:
        uuid:
          type: string
          format: uuid
        workspace_uuid:
          type: [string, 'null']
          format: uuid
        monitor_uuid:
          type: [string, 'null']
          format: uuid
        environment_uuid:
          type: [string, 'null']
          format: uuid
        status:
          type: string
        source:
          type: string
        queued_at:
          type: [string, 'null']
          format: date-time
        started_at:
          type: [string, 'null']
          format: date-time
        last_heartbeat_at:
          type: [string, 'null']
          format: date-time
        finished_at:
          type: [string, 'null']
          format: date-time
        duration_ms:
          type: [integer, 'null']
        exit_code:
          type: [integer, 'null']
        created_at:
          type: [string, 'null']
          format: date-time
        updated_at:
          type: [string, 'null']
          format: date-time
      required: [uuid, workspace_uuid, monitor_uuid, environment_uuid, status, source, queued_at, started_at, last_heartbeat_at, finished_at, duration_ms, exit_code, created_at, updated_at]
      additionalProperties: false
    Incident:
      type: object
      description: Allowlisted incident data. Dedupe keys, raw context, notification payloads, and actor details are intentionally absent.
      properties:
        uuid:
          type: string
          format: uuid
        workspace_uuid:
          type: [string, 'null']
          format: uuid
        monitor_uuid:
          type: [string, 'null']
          format: uuid
        run_uuid:
          type: [string, 'null']
          format: uuid
        parent_incident_uuid:
          type: [string, 'null']
          format: uuid
        type:
          type: string
        status:
          type: string
        severity:
          type: string
        title:
          type: string
        summary:
          type: [string, 'null']
        resolution_kind:
          type: [string, 'null']
        resolution_summary:
          type: [string, 'null']
        opened_at:
          type: [string, 'null']
          format: date-time
        acknowledged_at:
          type: [string, 'null']
          format: date-time
        muted_until:
          type: [string, 'null']
          format: date-time
        resolved_at:
          type: [string, 'null']
          format: date-time
        created_at:
          type: [string, 'null']
          format: date-time
        updated_at:
          type: [string, 'null']
          format: date-time
      required: [uuid, workspace_uuid, monitor_uuid, run_uuid, parent_incident_uuid, type, status, severity, title, summary, resolution_kind, resolution_summary, opened_at, acknowledged_at, muted_until, resolved_at, created_at, updated_at]
      additionalProperties: false

    ResourceLinks:
      type: object
      properties:
        first:
          type: [string, 'null']
        last:
          type: [string, 'null']
        prev:
          type: [string, 'null']
        next:
          type: [string, 'null']
      required: [first, last, prev, next]
      additionalProperties: false
    ResourceMeta:
      type: object
      properties:
        current_page:
          type: integer
        from:
          type: [integer, 'null']
        last_page:
          type: integer
        path:
          type: string
        per_page:
          type: integer
        to:
          type: [integer, 'null']
        total:
          type: integer
      required: [current_page, from, last_page, path, per_page, to, total]
      additionalProperties: true
    PaginatedWorkspaces:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/Workspace'
        links:
          $ref: '#/components/schemas/ResourceLinks'
        meta:
          $ref: '#/components/schemas/ResourceMeta'
      required: [data, links, meta]
    PaginatedProjects:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/Project'
        links:
          $ref: '#/components/schemas/ResourceLinks'
        meta:
          $ref: '#/components/schemas/ResourceMeta'
      required: [data, links, meta]
    PaginatedEnvironments:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/Environment'
        links:
          $ref: '#/components/schemas/ResourceLinks'
        meta:
          $ref: '#/components/schemas/ResourceMeta'
      required: [data, links, meta]
    PaginatedMonitors:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/Monitor'
        links:
          $ref: '#/components/schemas/ResourceLinks'
        meta:
          $ref: '#/components/schemas/ResourceMeta'
      required: [data, links, meta]
    PaginatedRuns:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/MonitorRun'
        links:
          $ref: '#/components/schemas/ResourceLinks'
        meta:
          $ref: '#/components/schemas/ResourceMeta'
      required: [data, links, meta]
    PaginatedIncidents:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/Incident'
        links:
          $ref: '#/components/schemas/ResourceLinks'
        meta:
          $ref: '#/components/schemas/ResourceMeta'
      required: [data, links, meta]

    WorkspaceResponse:
      type: object
      properties:
        data:
          $ref: '#/components/schemas/Workspace'
      required: [data]
    ProjectResponse:
      type: object
      properties:
        data:
          $ref: '#/components/schemas/Project'
      required: [data]
    EnvironmentResponse:
      type: object
      properties:
        data:
          $ref: '#/components/schemas/Environment'
      required: [data]
    MonitorResponse:
      type: object
      properties:
        data:
          $ref: '#/components/schemas/Monitor'
      required: [data]
    MonitorRunResponse:
      type: object
      properties:
        data:
          $ref: '#/components/schemas/MonitorRun'
      required: [data]
    IncidentResponse:
      type: object
      properties:
        data:
          $ref: '#/components/schemas/Incident'
      required: [data]
    WorkspaceOverviewResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            workspace:
              $ref: '#/components/schemas/Workspace'
            counts:
              type: object
              properties:
                projects: {type: integer}
                environments: {type: integer}
                monitors: {type: integer}
                active_monitors: {type: integer}
                runs: {type: integer}
                incidents: {type: integer}
                open_incidents: {type: integer}
              required: [projects, environments, monitors, active_monitors, runs, incidents, open_incidents]
              additionalProperties: false
            integration_evidence:
              type: object
              properties:
                started_at: {type: [string, 'null'], format: date-time}
                definition_sync_succeeded_at: {type: [string, 'null'], format: date-time}
                first_runtime_signal_at: {type: [string, 'null'], format: date-time}
              required: [started_at, definition_sync_succeeded_at, first_runtime_signal_at]
              additionalProperties: false
          required: [workspace, counts, integration_evidence]
          additionalProperties: false
      required: [data]
    ManagementMonitorSyncResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            project:
              $ref: '#/components/schemas/Project'
            environment:
              $ref: '#/components/schemas/Environment'
            monitors:
              type: array
              items:
                $ref: '#/components/schemas/Monitor'
          required: [project, environment, monitors]
          additionalProperties: false
      required: [data]
    ConfirmedIncidentReasonRequest:
      type: object
      properties:
        reason:
          type: string
          minLength: 3
          maxLength: 1000
        confirmed:
          type: boolean
          const: true
      required: [reason, confirmed]
      additionalProperties: true
    ConfirmedIncidentSilenceRequest:
      allOf:
        - $ref: '#/components/schemas/ConfirmedIncidentReasonRequest'
        - type: object
          properties:
            minutes:
              type: integer
              minimum: 5
              maximum: 10080
          required: [minutes]
    IncidentMutationResponse:
      type: object
      properties:
        data:
          $ref: '#/components/schemas/Incident'
        meta:
          type: object
          properties:
            changed:
              type: boolean
          required: [changed]
          additionalProperties: false
      required: [data, meta]
