openapi: "3.1.0"
info:
  title: Certack API
  description: |
    Infrastructure monitoring platform — SSL/TLS, Uptime, DNS, Domain expiry, Latency.
    Monitor your infrastructure with comprehensive checks and alerting.
  version: "1.0.0"
  contact:
    name: Certack Support
    email: support@certack.com
    url: https://certack.com/docs/api
  license:
    name: Proprietary
    url: https://certack.com/terms

servers:
  - url: https://app.certack.com
    description: Production

security:
  - BearerAuth: []

components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      description: "Bearer token authentication. Use your API key (sp_...) or Supabase JWT. API keys available on all plans."
    RateLimitAuth:
      type: apiKey
      in: header
      name: Authorization
      description: "Rate limiting is enforced per API key. Monthly call limits: Free=100, Starter=2,000, Pro=10,000, Team=50,000. QPS limits (per 10s window): Free=10, Starter=50, Pro=100, Team=300."

  schemas:
    Site:
      type: object
      properties:
        id:
          type: string
          format: uuid
        domain:
          type: string
        check_types:
          type: array
          items:
            type: string
            enum: [ssl, dns, domain, ct]
        custom_port:
          type: integer
          nullable: true
        origin_ip:
          type: string
          nullable: true
        alert_days:
          type: integer
          default: 14
        monitoring_enabled:
          type: boolean
        created_at:
          type: string
          format: date-time

    SSLCheckResult:
      type: object
      properties:
        valid:
          type: boolean
        issuer:
          type: string
        expires_at:
          type: string
          format: date-time
        days_remaining:
          type: integer
        san:
          type: array
          items:
            type: string
        chain:
          type: array
          items:
            type: object
        chain_complete:
          type: boolean
        chain_error:
          type: string
          nullable: true
        error:
          type: string
          nullable: true

    DNSCheckResult:
      type: object
      properties:
        records:
          type: array
          items:
            type: object
            properties:
              type:
                type: string
              values:
                type: array
                items:
                  type: string
        error:
          type: string
          nullable: true

    DomainCheckResult:
      type: object
      properties:
        registrar:
          type: string
          nullable: true
        expires_at:
          type: string
          format: date-time
          nullable: true
        days_remaining:
          type: integer
          nullable: true
        name_servers:
          type: array
          items:
            type: string
          nullable: true
        privacy_protected:
          type: boolean
          nullable: true
        error:
          type: string
          nullable: true

    CertHistoryResult:
      type: object
      properties:
        history:
          type: array
          items:
            type: object
            properties:
              fingerprint:
                type: string
              change_type:
                type: string
                enum: [renewal, replacement, issuer_change, san_change]
              changed_at:
                type: string
                format: date-time
              issuer:
                type: string
        total:
          type: integer

    UptimeCheckResult:
      type: object
      properties:
        status:
          type: string
          enum: [up, degraded, down]
        status_code:
          type: integer
        response_time_ms:
          type: number
        ttfb_ms:
          type: number
        keyword_match:
          type: boolean
          nullable: true
        error:
          type: string
          nullable: true

    Incident:
      type: object
      properties:
        id:
          type: string
          format: uuid
        title:
          type: string
        severity:
          type: string
          enum: [minor, major, critical]
        affected_sites:
          type: array
          items:
            type: string
            format: uuid
          nullable: true
        auto_create:
          type: boolean
        status:
          type: string
          enum: [investigating, identified, monitoring, resolved]
        updates:
          type: array
          items:
            type: object
            properties:
              status:
                type: string
                enum: [investigating, identified, monitoring, resolved]
              message:
                type: string
              created_at:
                type: string
                format: date-time
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    MaintenanceWindow:
      type: object
      properties:
        id:
          type: string
          format: uuid
        site_id:
          type: string
          format: uuid
          nullable: true
        starts_at:
          type: string
          format: date-time
        ends_at:
          type: string
          format: date-time
        description:
          type: string
          nullable: true
        created_at:
          type: string
          format: date-time

    TeamMember:
      type: object
      properties:
        id:
          type: string
          format: uuid
        email:
          type: string
        role:
          type: string
          enum: [admin, editor, viewer]
        status:
          type: string
          enum: [active, pending]
        joined_at:
          type: string
          format: date-time
          nullable: true

    NotificationSettings:
      type: object
      properties:
        email:
          type: boolean
        slack_webhook_url:
          type: string
          nullable: true
        discord_webhook_url:
          type: string
          nullable: true
        teams_webhook:
          type: string
          nullable: true
        custom_webhook_url:
          type: string
          nullable: true

    Alert:
      type: object
      properties:
        id:
          type: string
          format: uuid
        type:
          type: string
          enum: [ssl, dns, domain, ct, cert_change]
        severity:
          type: string
          enum: [info, warning, critical]
        message:
          type: string
        suggestion:
          type: string
          nullable: true
        is_resolved:
          type: boolean
        site_id:
          type: string
          format: uuid
        created_at:
          type: string
          format: date-time

    Error:
      type: object
      properties:
        error:
          type: string
        message:
          type: string

    RateLimitError:
      type: object
      properties:
        error:
          type: string
          example: "Rate limit exceeded"
        message:
          type: string
          example: "Monthly API call limit exceeded. Upgrade your plan for more calls."
        retry_after:
          type: integer
          description: Seconds until the rate limit resets
          nullable: true

paths:
  /api/sites:
    get:
      summary: List monitored sites
      operationId: listSites
      responses:
        "200":
          description: List of sites
          content:
            application/json:
              schema:
                type: object
                properties:
                  sites:
                    type: array
                    items:
                      $ref: "#/components/schemas/Site"
                  plan:
                    type: string
                  userId:
                    type: string
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "429":
          description: Rate limit exceeded
          headers:
            X-RateLimit-Limit:
              schema:
                type: integer
              description: Maximum requests per minute
            X-RateLimit-Remaining:
              schema:
                type: integer
              description: Remaining requests in current window
            X-RateLimit-Reset:
              schema:
                type: integer
              description: Unix timestamp when the window resets
            X-MonthlyLimit-Limit:
              schema:
                type: integer
              description: Monthly API call limit for your plan
            X-MonthlyLimit-Used:
              schema:
                type: integer
              description: API calls used this month
            X-MonthlyLimit-Remaining:
              schema:
                type: integer
              description: API calls remaining this month
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitError"

    post:
      summary: Add a new site
      operationId: createSite
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [domain]
              properties:
                domain:
                  type: string
                custom_port:
                  type: integer
                origin_ip:
                  type: string
                alert_days:
                  type: integer
                check_types:
                  type: array
                  items:
                    type: string
                dns_provider:
                  type: string
                dns_provider_config:
                  type: object
                deploy_target:
                  type: string
                deploy_config:
                  type: object
      responses:
        "200":
          description: Site created
          content:
            application/json:
              schema:
                type: object
                properties:
                  site:
                    $ref: "#/components/schemas/Site"
        "400":
          description: Bad request
        "401":
          description: Unauthorized
        "403":
          description: Plan limit reached
        "429":
          description: Rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitError"

  /api/sites?id={site_id}:
    patch:
      summary: Update site configuration
      operationId: updateSite
      parameters:
        - name: site_id
          in: query
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                custom_port:
                  type: integer
                origin_ip:
                  type: string
                alert_days:
                  type: integer
                check_types:
                  type: array
                  items:
                    type: string
                dns_provider:
                  type: string
                dns_provider_config:
                  type: object
                deploy_target:
                  type: string
                deploy_config:
                  type: object
      responses:
        "200":
          description: Site updated
        "401":
          description: Unauthorized
        "404":
          description: Site not found

    delete:
      summary: Remove a site
      operationId: deleteSite
      parameters:
        - name: site_id
          in: query
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: Site deleted
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
        "401":
          description: Unauthorized
        "404":
          description: Site not found

  /api/check-ssl:
    post:
      summary: Run SSL/TLS certificate check
      operationId: checkSSL
      description: Free+ plan required. QPS and monthly limits apply per plan.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [domain]
              properties:
                domain:
                  type: string
                port:
                  type: integer
                  default: 443
                origin_ip:
                  type: string
                site_id:
                  type: string
                  format: uuid
      responses:
        "200":
          description: SSL/TLS check result
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SSLCheckResult"
        "401":
          description: Unauthorized

  /api/check-dns:
    post:
      summary: Run DNS record check
      operationId: checkDNS
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [domain]
              properties:
                domain:
                  type: string
                site_id:
                  type: string
                  format: uuid
      responses:
        "200":
          description: DNS check result
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DNSCheckResult"
        "401":
          description: Unauthorized

  /api/check-domain:
    post:
      summary: Run domain expiry check
      operationId: checkDomain
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [domain]
              properties:
                domain:
                  type: string
                site_id:
                  type: string
                  format: uuid
      responses:
        "200":
          description: Domain check result
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DomainCheckResult"
        "401":
          description: Unauthorized

  /api/checks:
    get:
      summary: Get check history
      operationId: getChecks
      parameters:
        - name: site_id
          in: query
          required: true
          schema:
            type: string
            format: uuid
        - name: check_type
          in: query
          schema:
            type: string
            enum: [ssl, dns, domain, ct, uptime]
        - name: from
          in: query
          schema:
            type: string
        - name: to
          in: query
          schema:
            type: string
        - name: limit
          in: query
          schema:
            type: integer
            default: 50
            maximum: 200
        - name: offset
          in: query
          schema:
            type: integer
            default: 0
      responses:
        "200":
          description: Check results
          content:
            application/json:
              schema:
                type: object
                properties:
                  checks:
                    type: array
                    items:
                      type: object
                  total:
                    type: integer
                  limit:
                    type: integer
                  offset:
                    type: integer
        "401":
          description: Unauthorized

  /api/alerts:
    get:
      summary: List alerts
      operationId: listAlerts
      parameters:
        - name: type
          in: query
          schema:
            type: string
            enum: [ssl, dns, domain, ct, cert_change]
        - name: severity
          in: query
          schema:
            type: string
            enum: [info, warning, critical]
        - name: resolved
          in: query
          schema:
            type: string
        - name: limit
          in: query
          schema:
            type: integer
            default: 50
        - name: offset
          in: query
          schema:
            type: integer
            default: 0
      responses:
        "200":
          description: Alert list
          content:
            application/json:
              schema:
                type: object
                properties:
                  alerts:
                    type: array
                    items:
                      $ref: "#/components/schemas/Alert"
                  total:
                    type: integer
        "401":
          description: Unauthorized

  /api/alerts?id={alert_id}:
    patch:
      summary: Resolve an alert
      operationId: resolveAlert
      parameters:
        - name: alert_id
          in: query
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                is_resolved:
                  type: boolean
      responses:
        "200":
          description: Alert resolved
          content:
            application/json:
              schema:
                type: object
                properties:
                  alert:
                    $ref: "#/components/schemas/Alert"
        "401":
          description: Unauthorized
        "404":
          description: Alert not found

  /api/account:
    get:
      summary: Get account info
      operationId: getAccount
      description: Retrieve the authenticated user's account info, including their active plan.
      responses:
        "200":
          description: Account info
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                    format: uuid
                  email:
                    type: string
                  full_name:
                    type: string
                    nullable: true
                  plan:
                    type: string
                    enum: [free, pro, team]
                  created_at:
                    type: string
                    format: date-time
        "401":
          description: Unauthorized
        "404":
          description: Profile not found

    patch:
      summary: Update account profile
      operationId: updateAccount
      description: Update the authenticated user's account profile (e.g. display name).
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                full_name:
                  type: string
                  maxLength: 200
      responses:
        "200":
          description: Updated profile
          content:
            application/json:
              schema:
                type: object
                properties:
                  profile:
                    type: object
                    properties:
                      id:
                        type: string
                        format: uuid
                      email:
                        type: string
                      full_name:
                        type: string
                        nullable: true
                      plan:
                        type: string
                      created_at:
                        type: string
                        format: date-time
        "400":
          description: No fields to update or invalid JSON
        "401":
          description: Unauthorized

    delete:
      summary: Delete account
      operationId: deleteAccount
      description: |
        Permanently deletes the user account and all associated data (sites, checks, alerts,
        API keys, profile). Any active Creem subscription is cancelled first.
      responses:
        "200":
          description: Account deleted
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
        "401":
          description: Unauthorized
        "503":
          description: Server not configured

  /api/auth/local-register:
    post:
      summary: Register a local account (Electron only)
      operationId: localRegister
      description: |
        Create a new local account in Electron / self-hosted mode. Password is hashed with bcrypt
        and a JWT is returned in the response body and set as an HTTP-only cookie.
        Returns 409 if the email is already registered. Not available in SaaS mode.
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [email, password]
              properties:
                email:
                  type: string
                  format: email
                password:
                  type: string
                  minLength: 8
      responses:
        "200":
          description: Account created
          content:
            application/json:
              schema:
                type: object
                properties:
                  user:
                    type: object
                    properties:
                      id:
                        type: string
                        format: uuid
                      email:
                        type: string
                      plan:
                        type: string
                  token:
                    type: string
        "400":
          description: Missing fields, invalid email, or password too short
        "409":
          description: Email already registered

  /api/auth/local-login:
    post:
      summary: Login with email and password (Electron only)
      operationId: localLogin
      description: |
        Authenticate with email and password in Electron / self-hosted mode. On success, returns
        the user object and a JWT valid for 7 days. Returns 401 for invalid credentials.
        Not available in SaaS mode.
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [email, password]
              properties:
                email:
                  type: string
                  format: email
                password:
                  type: string
      responses:
        "200":
          description: Login successful
          content:
            application/json:
              schema:
                type: object
                properties:
                  user:
                    type: object
                    properties:
                      id:
                        type: string
                        format: uuid
                      email:
                        type: string
                      plan:
                        type: string
                  token:
                    type: string
        "400":
          description: Email and password are required
        "401":
          description: Invalid email or password

  /api/auth/welcome:
    get:
      summary: Pre-signup anti-abuse check
      operationId: checkSignupAllowed
      description: |
        Verify the requesting IP is allowed to create a new free-tier account.
        Returns 403 with a reason if the IP has created too many free accounts.
      security: []
      responses:
        "200":
          description: Signup allowed
          content:
            application/json:
              schema:
                type: object
                properties:
                  allowed:
                    type: boolean
        "403":
          description: Signup blocked
          content:
            application/json:
              schema:
                type: object
                properties:
                  allowed:
                    type: boolean
                  reason:
                    type: string
        "503":
          description: Unable to verify signup eligibility
    post:
      summary: Send welcome email
      operationId: sendWelcomeEmail
      description: |
        Trigger the welcome email for a newly signed-up user. Idempotent — only sends
        if the user was created within the last 5 minutes.
      responses:
        "200":
          description: Welcome email result
          content:
            application/json:
              schema:
                type: object
                properties:
                  sent:
                    type: boolean
        "401":
          description: Not authenticated

  /api/checkout:
    post:
      summary: Create a checkout session
      operationId: createCheckout
      description: |
        Create a Creem checkout session for upgrading to a paid plan. Returns a hosted
        checkout URL to redirect the user's browser. Only upgrades are allowed; downgrades
        are handled by cancelling the existing subscription.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [planId]
              properties:
                planId:
                  type: string
                  enum: [pro, team]
                billing:
                  type: string
                  enum: [monthly, yearly]
                  default: monthly
                email:
                  type: string
                  format: email
      responses:
        "200":
          description: Checkout session created
          content:
            application/json:
              schema:
                type: object
                properties:
                  checkoutUrl:
                    type: string
        "400":
          description: Invalid plan, invalid billing cycle, or already on this/higher plan
        "401":
          description: Authentication required
        "413":
          description: Request body too large (>10KB)
        "503":
          description: Payment system (Creem) is not configured

  /api/checkout/verify:
    post:
      summary: Verify a Creem checkout redirect signature
      operationId: verifyCheckout
      description: |
        Verify the HMAC-SHA256 signature on a Creem redirect after checkout. Ensures the
        userId matches the authenticated user and applies the plan immediately.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                signature:
                  type: string
                product_id:
                  type: string
                customer_id:
                  type: string
                userId:
                  type: string
      responses:
        "200":
          description: Checkout verified
          content:
            application/json:
              schema:
                type: object
                properties:
                  verified:
                    type: boolean
                  checkout:
                    type: object
        "401":
          description: Unauthorized or invalid checkout signature
        "403":
          description: User ID mismatch

  /api/api-keys:
    get:
      summary: List API keys
      operationId: listApiKeys
      description: API keys available on all plans. Key limits: Free (1 key), Pro (5), Team (10).
      responses:
        "200":
          description: API key list
          content:
            application/json:
              schema:
                type: object
                properties:
                  keys:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          format: uuid
                        name:
                          type: string
                        prefix:
                          type: string
                        last_used_at:
                          type: string
                          format: date-time
                          nullable: true
                        created_at:
                          type: string
                          format: date-time
        "401":
          description: Unauthorized

    post:
      summary: Create API key
      operationId: createApiKey
      description: API keys available on all plans. Key limits: Free (1 key), Pro (5), Team (10).
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name]
              properties:
                name:
                  type: string
      responses:
        "200":
          description: API key created
          content:
            application/json:
              schema:
                type: object
                properties:
                  key:
                    type: string
                  prefix:
                    type: string
                  name:
                    type: string
        "401":
          description: Unauthorized

  /api/api-keys?id={key_id}:
    delete:
      summary: Delete API key
      operationId: deleteApiKey
      parameters:
        - name: key_id
          in: query
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: Key deleted
        "401":
          description: Unauthorized

  /api/cert-history:
    get:
      summary: Get certificate change history
      operationId: getCertHistory
      parameters:
        - name: site_id
          in: query
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: Certificate history
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CertHistoryResult"
        "401":
          description: Unauthorized

  /api/team:
    get:
      summary: List team members
      operationId: listTeamMembers
      description: Team+ plan required
      responses:
        "200":
          description: Team member list
          content:
            application/json:
              schema:
                type: object
                properties:
                  members:
                    type: array
                    items:
                      $ref: "#/components/schemas/TeamMember"
        "401":
          description: Unauthorized
        "403":
          description: Team+ plan required

    post:
      summary: Invite team member
      operationId: inviteTeamMember
      description: Team+ plan required
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [email, role]
              properties:
                email:
                  type: string
                  format: email
                role:
                  type: string
                  enum: [admin, editor, viewer]
      responses:
        "200":
          description: Invitation sent
          content:
            application/json:
              schema:
                type: object
                properties:
                  member:
                    $ref: "#/components/schemas/TeamMember"
        "401":
          description: Unauthorized
        "403":
          description: Team+ plan required

  /api/team/role:
    patch:
      summary: Change team member role
      operationId: changeTeamRole
      description: Team+ plan required
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [member_id, role]
              properties:
                member_id:
                  type: string
                  format: uuid
                role:
                  type: string
                  enum: [admin, editor, viewer]
      responses:
        "200":
          description: Role updated
          content:
            application/json:
              schema:
                type: object
                properties:
                  member:
                    $ref: "#/components/schemas/TeamMember"
        "401":
          description: Unauthorized
        "403":
          description: Team+ plan required
        "404":
          description: Member not found

  /api/team/accept:
    post:
      summary: Accept team invitation
      operationId: acceptTeamInvitation
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [token]
              properties:
                token:
                  type: string
      responses:
        "200":
          description: Invitation accepted
          content:
            application/json:
              schema:
                type: object
                properties:
                  member:
                    $ref: "#/components/schemas/TeamMember"
        "401":
          description: Unauthorized
        "400":
          description: Invalid or expired token

  /api/incidents:
    get:
      summary: List incidents
      operationId: listIncidents
      responses:
        "200":
          description: Incident list
          content:
            application/json:
              schema:
                type: object
                properties:
                  incidents:
                    type: array
                    items:
                      $ref: "#/components/schemas/Incident"
                  total:
                    type: integer
        "401":
          description: Unauthorized

    post:
      summary: Create incident
      operationId: createIncident
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [title]
              properties:
                title:
                  type: string
                severity:
                  type: string
                  enum: [minor, major, critical]
                affected_sites:
                  type: array
                  items:
                    type: string
                    format: uuid
                auto_create:
                  type: boolean
      responses:
        "200":
          description: Incident created
          content:
            application/json:
              schema:
                type: object
                properties:
                  incident:
                    $ref: "#/components/schemas/Incident"
        "401":
          description: Unauthorized

  /api/incidents/{id}/updates:
    post:
      summary: Add incident update
      operationId: addIncidentUpdate
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [status, message]
              properties:
                status:
                  type: string
                  enum: [investigating, identified, monitoring, resolved]
                message:
                  type: string
      responses:
        "200":
          description: Update added
          content:
            application/json:
              schema:
                type: object
                properties:
                  incident:
                    $ref: "#/components/schemas/Incident"
        "401":
          description: Unauthorized
        "404":
          description: Incident not found

  /api/maintenance-windows:
    get:
      summary: List maintenance windows
      operationId: listMaintenanceWindows
      responses:
        "200":
          description: Maintenance window list
          content:
            application/json:
              schema:
                type: object
                properties:
                  windows:
                    type: array
                    items:
                      $ref: "#/components/schemas/MaintenanceWindow"
                  total:
                    type: integer
        "401":
          description: Unauthorized

    post:
      summary: Create maintenance window
      operationId: createMaintenanceWindow
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [starts_at, ends_at]
              properties:
                site_id:
                  type: string
                  format: uuid
                starts_at:
                  type: string
                  format: date-time
                ends_at:
                  type: string
                  format: date-time
                description:
                  type: string
      responses:
        "200":
          description: Maintenance window created
          content:
            application/json:
              schema:
                type: object
                properties:
                  window:
                    $ref: "#/components/schemas/MaintenanceWindow"
        "401":
          description: Unauthorized

    delete:
      summary: Delete maintenance window
      operationId: deleteMaintenanceWindow
      parameters:
        - name: id
          in: query
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: Maintenance window deleted
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
        "401":
          description: Unauthorized
        "404":
          description: Maintenance window not found

  /api/settings/notifications:
    get:
      summary: Get notification settings
      operationId: getNotificationSettings
      responses:
        "200":
          description: Notification settings
          content:
            application/json:
              schema:
                type: object
                properties:
                  settings:
                    $ref: "#/components/schemas/NotificationSettings"
        "401":
          description: Unauthorized

    patch:
      summary: Update notification settings
      operationId: updateNotificationSettings
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                email:
                  type: boolean
                slack_webhook_url:
                  type: string
                discord_webhook_url:
                  type: string
                teams_webhook:
                  type: string
                custom_webhook_url:
                  type: string
      responses:
        "200":
          description: Settings updated
          content:
            application/json:
              schema:
                type: object
                properties:
                  settings:
                    $ref: "#/components/schemas/NotificationSettings"
        "401":
          description: Unauthorized
        "403":
          description: Plan restriction

    post:
      summary: Send test notification
      operationId: sendTestNotification
      responses:
        "200":
          description: Test notification sent
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  channels:
                    type: array
                    items:
                      type: string
        "401":
          description: Unauthorized

  /api/mcp:
    post:
      summary: MCP endpoint (JSON-RPC 2.0)
      operationId: mcpEndpoint
      description: |
        Model Context Protocol endpoint supporting JSON-RPC 2.0 requests.
        Available methods: initialize, tools/list, tools/call, ping
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [jsonrpc, id, method]
              properties:
                jsonrpc:
                  type: string
                  enum: ["2.0"]
                id:
                  type: integer
                method:
                  type: string
                  enum: [initialize, "tools/list", "tools/call", ping]
                params:
                  type: object
      responses:
        "200":
          description: JSON-RPC response
          content:
            application/json:
              schema:
                type: object
                properties:
                  jsonrpc:
                    type: string
                    enum: ["2.0"]
                  id:
                    type: integer
                  result:
                    type: object
                  error:
                    type: object
                    properties:
                      code:
                        type: integer
                      message:
                        type: string
        "401":
          description: Unauthorized

  /api/renewal:
    post:
      summary: Trigger certificate renewal
      operationId: triggerRenewal
      deprecated: true
      description: Deprecated — not available to new users. Pro+ plan required. Triggers renewal via Let's Encrypt.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [site_id]
              properties:
                site_id:
                  type: string
                  format: uuid
      responses:
        "200":
          description: Renewal initiated
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  site_id:
                    type: string
        "401":
          description: Unauthorized
        "403":
          description: Pro+ plan required

    get:
      summary: Get renewal logs
      operationId: getRenewalLogs
      deprecated: true
      description: Deprecated — not available to new users.
      parameters:
        - name: site_id
          in: query
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: Renewal logs
          content:
            application/json:
              schema:
                type: object
                properties:
                  logs:
                    type: array
                    items:
                      type: object
                      properties:
                        status:
                          type: string
                          enum: [pending, success, failed]
                        message:
                          type: string
                        created_at:
                          type: string
                          format: date-time
        "401":
          description: Unauthorized

  /api/webhooks/creem:
    post:
      summary: Creem payment webhook
      operationId: creemWebhook
      description: Webhook endpoint for Creem payment events. Called by Creem, not by users.
      security: []
      responses:
        "200":
          description: Webhook processed

  /api/public/check-ssl:
    get:
      summary: Public SSL/TLS check (no auth)
      operationId: publicCheckSSL
      security: []
      parameters:
        - name: domain
          in: query
          required: true
          schema:
            type: string
      responses:
        "200":
          description: SSL/TLS check result
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SSLCheckResult"
        "429":
          description: Rate limited (10 req/min per IP)
