openapi: 3.1.0
info:
  title: Kōdo Status Page API
  description: |
    API for managing status pages, incidents, services, and monitoring.

    ## Authentication
    All API requests require authentication via the `X-API-Key` header:
    ```
    X-API-Key: your_api_key_here
    ```

    You can find your API key in the [Dashboard Settings](/dashboard/api).

    ## Rate Limits
    - 1000 requests per minute per API key
    - Heartbeat endpoints: 10,000 requests per minute

    ## Errors
    All errors return a JSON object with an `error` field:
    ```json
    {
      "error": "Description of what went wrong"
    }
    ```
  version: 1.0.0
  contact:
    name: Kōdo Support
    email: support@kodostatus.com
  license:
    name: MIT

servers:
  - url: https://kodostatus.com/api/v1
    description: Production
  - url: http://localhost:3000/api/v1
    description: Local Development

tags:
  - name: Incidents
    description: Create and manage incidents
  - name: Services
    description: Manage services/components
  - name: Heartbeat
    description: Internal monitoring heartbeats
  - name: Metrics
    description: Push internal metrics

security:
  - ApiKeyAuth: []

paths:
  /incidents:
    get:
      tags:
        - Incidents
      summary: List incidents
      description: Get all incidents for your organization
      operationId: listIncidents
      parameters:
        - name: status
          in: query
          description: Filter by status
          schema:
            type: string
            enum: [investigating, identified, monitoring, resolved]
        - name: limit
          in: query
          description: Maximum number of incidents to return
          schema:
            type: integer
            default: 50
            maximum: 100
      responses:
        '200':
          description: List of incidents
          content:
            application/json:
              schema:
                type: object
                properties:
                  incidents:
                    type: array
                    items:
                      $ref: '#/components/schemas/Incident'
        '401':
          $ref: '#/components/responses/Unauthorized'

    post:
      tags:
        - Incidents
      summary: Create incident
      description: Create a new incident and optionally notify subscribers
      operationId: createIncident
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateIncidentRequest'
            examples:
              basic:
                summary: Basic incident
                value:
                  title: "Database connectivity issues"
                  status: investigating
                  severity: major
              with_message:
                summary: With initial message
                value:
                  title: "API latency spike"
                  status: investigating
                  severity: minor
                  message: "We are investigating reports of slow API responses"
                  services: ["API", "Database"]
      responses:
        '201':
          description: Incident created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Incident'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /incidents/{incidentId}:
    parameters:
      - name: incidentId
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: Incident ID

    get:
      tags:
        - Incidents
      summary: Get incident
      description: Get a single incident by ID
      operationId: getIncident
      responses:
        '200':
          description: Incident details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Incident'
        '404':
          $ref: '#/components/responses/NotFound'

    patch:
      tags:
        - Incidents
      summary: Update incident
      description: Update an incident status or add an update message
      operationId: updateIncident
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateIncidentRequest'
            examples:
              resolve:
                summary: Resolve incident
                value:
                  status: resolved
                  message: "Issue has been fixed. Root cause was a misconfigured connection pool."
              update:
                summary: Add update
                value:
                  status: identified
                  message: "We have identified the issue and are working on a fix."
      responses:
        '200':
          description: Incident updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Incident'
        '404':
          $ref: '#/components/responses/NotFound'

    delete:
      tags:
        - Incidents
      summary: Delete incident
      description: Permanently delete an incident
      operationId: deleteIncident
      responses:
        '200':
          description: Incident deleted
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
        '404':
          $ref: '#/components/responses/NotFound'

  /services:
    get:
      tags:
        - Services
      summary: List services
      description: Get all services for your organization
      operationId: listServices
      responses:
        '200':
          description: List of services
          content:
            application/json:
              schema:
                type: object
                properties:
                  services:
                    type: array
                    items:
                      $ref: '#/components/schemas/Service'

    post:
      tags:
        - Services
      summary: Create service
      description: Create a new service/component
      operationId: createService
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateServiceRequest'
            example:
              name: "Payment Gateway"
              description: "Handles all payment processing"
      responses:
        '201':
          description: Service created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Service'

  /services/{serviceId}:
    parameters:
      - name: serviceId
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: Service ID

    get:
      tags:
        - Services
      summary: Get service
      description: Get a single service by ID
      operationId: getService
      responses:
        '200':
          description: Service details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Service'
        '404':
          $ref: '#/components/responses/NotFound'

    patch:
      tags:
        - Services
      summary: Update service
      description: Update service name, description, or status
      operationId: updateService
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateServiceRequest'
            examples:
              status:
                summary: Update status
                value:
                  status: degraded
              maintenance:
                summary: Set maintenance
                value:
                  status: maintenance
      responses:
        '200':
          description: Service updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Service'

    delete:
      tags:
        - Services
      summary: Delete service
      description: Permanently delete a service
      operationId: deleteService
      responses:
        '200':
          description: Service deleted
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean

  /heartbeat/{monitorId}:
    post:
      tags:
        - Heartbeat
      summary: Send heartbeat
      description: |
        Send a heartbeat ping for cron jobs, background workers, or scheduled tasks.
        If a heartbeat isn't received within the expected interval, the service is marked as down.
      operationId: sendHeartbeat
      security: []  # Heartbeat uses token in URL, not API key
      parameters:
        - name: monitorId
          in: path
          required: true
          schema:
            type: string
          description: Monitor ID or token
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/HeartbeatRequest'
            examples:
              simple:
                summary: Simple ping
                value: {}
              detailed:
                summary: With status
                value:
                  status: up
                  response_time_ms: 1523
                  message: "Backup completed successfully"
      responses:
        '200':
          description: Heartbeat recorded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HeartbeatResponse'

  /metrics/ingest:
    post:
      tags:
        - Metrics
      summary: Push metrics
      description: |
        Push internal metrics for a service. Kōdo automatically determines service health based on thresholds.

        **Auto-health detection thresholds:**
        - error_rate > 50% → major_outage
        - error_rate > 10% → partial_outage
        - error_rate > 1% → degraded
        - response_time > 5000ms → degraded
        - cpu_percent > 90% → degraded
      operationId: ingestMetrics
      security: []  # Uses api_key in body
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MetricsRequest'
            example:
              api_key: "your_api_key"
              service: "API Gateway"
              metrics:
                error_rate: 2.5
                response_time_ms: 245
                cpu_percent: 65
                memory_percent: 78
      responses:
        '200':
          description: Metrics received
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MetricsResponse'

components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
      description: Your organization API key

  schemas:
    Incident:
      type: object
      properties:
        id:
          type: string
          format: uuid
        title:
          type: string
        status:
          type: string
          enum: [investigating, identified, monitoring, resolved]
        severity:
          type: string
          enum: [minor, major, critical]
        started_at:
          type: string
          format: date-time
        resolved_at:
          type: string
          format: date-time
          nullable: true
        created_at:
          type: string
          format: date-time
        updates:
          type: array
          items:
            $ref: '#/components/schemas/IncidentUpdate'
        services:
          type: array
          items:
            $ref: '#/components/schemas/ServiceRef'

    IncidentUpdate:
      type: object
      properties:
        id:
          type: string
          format: uuid
        status:
          type: string
          enum: [investigating, identified, monitoring, resolved]
        message:
          type: string
        created_at:
          type: string
          format: date-time

    ServiceRef:
      type: object
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string

    Service:
      type: object
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
        description:
          type: string
          nullable: true
        status:
          type: string
          enum: [operational, degraded, partial_outage, major_outage, maintenance]
        display_order:
          type: integer
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    CreateIncidentRequest:
      type: object
      required:
        - title
      properties:
        title:
          type: string
          description: Incident title
          example: "Database connectivity issues"
        status:
          type: string
          enum: [investigating, identified, monitoring, resolved]
          default: investigating
        severity:
          type: string
          enum: [minor, major, critical]
          default: minor
        message:
          type: string
          description: Initial update message
        services:
          type: array
          items:
            type: string
          description: Service names or IDs to link

    UpdateIncidentRequest:
      type: object
      properties:
        status:
          type: string
          enum: [investigating, identified, monitoring, resolved]
        message:
          type: string
          description: Update message
        title:
          type: string
        severity:
          type: string
          enum: [minor, major, critical]

    CreateServiceRequest:
      type: object
      required:
        - name
      properties:
        name:
          type: string
          example: "Payment Gateway"
        description:
          type: string
          example: "Handles all payment processing"
        status:
          type: string
          enum: [operational, degraded, partial_outage, major_outage, maintenance]
          default: operational

    UpdateServiceRequest:
      type: object
      properties:
        name:
          type: string
        description:
          type: string
        status:
          type: string
          enum: [operational, degraded, partial_outage, major_outage, maintenance]

    HeartbeatRequest:
      type: object
      properties:
        status:
          type: string
          enum: [up, down, degraded]
        response_time_ms:
          type: integer
        message:
          type: string

    HeartbeatResponse:
      type: object
      properties:
        success:
          type: boolean
        recorded_at:
          type: string
          format: date-time
        monitor_status:
          type: string

    MetricsRequest:
      type: object
      required:
        - api_key
        - metrics
      properties:
        api_key:
          type: string
        service:
          type: string
          description: Service name to update
        metrics:
          type: object
          properties:
            error_rate:
              type: number
              description: Error percentage (0-100)
            response_time_ms:
              type: number
              description: Average response time in milliseconds
            cpu_percent:
              type: number
              description: CPU usage (0-100)
            memory_percent:
              type: number
              description: Memory usage (0-100)
            db_latency_ms:
              type: number
              description: Database latency in milliseconds
            queue_depth:
              type: integer
              description: Items in queue
            custom:
              type: object
              additionalProperties:
                type: number
        timestamp:
          type: string
          format: date-time

    MetricsResponse:
      type: object
      properties:
        success:
          type: boolean
        received_at:
          type: string
          format: date-time
        health_status:
          type: string
          enum: [operational, degraded, partial_outage, major_outage]
        alerts:
          type: array
          items:
            type: string

    Error:
      type: object
      properties:
        error:
          type: string
          description: Error message

  responses:
    Unauthorized:
      description: Invalid or missing API key
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: "Invalid API key"

    BadRequest:
      description: Invalid request parameters
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: "Title is required"

    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: "Incident not found"
