openapi: 3.0.3
info:
  title: SaaS DNS API
  description: REST API for managing DNS filtering clients, profiles and analytics.
  version: "1.0"

servers:
  - url: https://{domain}
    variables:
      domain:
        default: saas.unveildns.com

security:
  - ApiKeyAuth: []

components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
      description: API key generated from the Account page (admin/partner only)

  schemas:
    User:
      type: object
      properties:
        user_id:
          type: string
          example: "e20accdb06c51ce06e576139346999d73a3d"
        email:
          type: string
          example: "client@example.com"
        name:
          type: string
          example: "John Doe"
        plan:
          type: string
          enum: [free, pro]
          example: "free"
        email_verified:
          type: boolean
        is_admin:
          type: boolean
        is_partner:
          type: boolean
        created_at:
          type: string
        profile_count:
          type: integer
        country:
          type: string
        effective_quota:
          type: integer
        monthly_queries:
          type: integer

    Profile:
      type: object
      properties:
        config_id:
          type: string
          example: "a1b2c3d4e5f6"
        name:
          type: string
          example: "My Profile"
        dns_preset:
          type: string
          enum: [no_filtering, security, family]
        safe_search:
          type: boolean
        youtube_restricted_mode:
          type: boolean
        block_canary:
          type: boolean
        block_telemetry:
          type: boolean
        block_cname_cloaking:
          type: boolean
        safe_browsing:
          type: boolean
        block_nrd:
          type: boolean
        block_dga:
          type: boolean
        block_cybersquatting:
          type: boolean
        block_fastflux:
          type: boolean
        block_rebinding:
          type: boolean
        block_malicious_ips:
          type: boolean
        block_exfiltration:
          type: boolean
        block_dyndns:
          type: boolean
        block_tunneling:
          type: boolean
        block_any:
          type: boolean
        anonymous_dns:
          type: boolean
        dns_prefetch:
          type: boolean
        cache_ttl_hours:
          type: integer
        blocked_ttl:
          type: integer
        override_ttl:
          type: integer
        allowlist:
          type: object
          properties:
            enabled:
              type: boolean
            domains:
              type: array
              items:
                type: string
        denylist:
          type: object
          properties:
            enabled:
              type: boolean
            domains:
              type: array
              items:
                type: string
        blocked_services:
          type: object
          properties:
            enabled:
              type: boolean
            services:
              type: array
              items:
                type: string
        blocked_categories:
          type: object
          properties:
            enabled:
              type: boolean
            categories:
              type: array
              items:
                type: string
        blocked_tlds:
          type: object
          properties:
            enabled:
              type: boolean
            tlds:
              type: array
              items:
                type: string
        blocked_countries:
          type: object
          properties:
            enabled:
              type: boolean
            countries:
              type: array
              items:
                type: string
        ede:
          type: object
          properties:
            enabled:
              type: boolean
            message:
              type: string
        linked_ips:
          type: array
          items:
            type: string
        linked_hostnames:
          type: array
          items:
            type: string
        devices:
          type: array
          items:
            type: object
            properties:
              name:
                type: string
              slug:
                type: string
              type:
                type: string
              mode:
                type: string

    Stats:
      type: object
      properties:
        total_queries:
          type: integer
        blocked_queries:
          type: integer
        blocked_percentage:
          type: number
        avg_latency_ms:
          type: number
        cache_hit_rate:
          type: number

    Error:
      type: object
      properties:
        error:
          type: string

paths:
  /api/admin/users:
    get:
      summary: List all clients
      tags: [Client Management]
      responses:
        "200":
          description: List of clients
          content:
            application/json:
              schema:
                type: object
                properties:
                  users:
                    type: array
                    items:
                      $ref: "#/components/schemas/User"
    post:
      summary: Create a new client account
      tags: [Client Management]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [email, password]
              properties:
                email:
                  type: string
                password:
                  type: string
                name:
                  type: string
                notify:
                  type: boolean
                  description: Send welcome email with credentials
      responses:
        "201":
          description: Account created

  /api/admin/users/{user_id}/plan:
    put:
      summary: Change a client's plan
      tags: [Client Management]
      parameters:
        - name: user_id
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [plan]
              properties:
                plan:
                  type: string
                  enum: [free, pro]
      responses:
        "200":
          description: Plan updated

  /api/admin/users/{user_id}:
    delete:
      summary: Delete a client account
      tags: [Client Management]
      parameters:
        - name: user_id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Account deleted

  /api/admin/users/{user_id}/profiles:
    get:
      summary: List a client's profiles
      tags: [Client Profiles]
      parameters:
        - name: user_id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: List of profiles
          content:
            application/json:
              schema:
                type: object
                properties:
                  profiles:
                    type: array
                    items:
                      $ref: "#/components/schemas/Profile"

  /api/admin/users/{user_id}/profiles/{config_id}:
    get:
      summary: Get a client's profile details
      tags: [Client Profiles]
      parameters:
        - name: user_id
          in: path
          required: true
          schema:
            type: string
        - name: config_id
          in: path
          required: true
          schema:
            type: string
            example: a1b2c3d4e5f6
      responses:
        "200":
          description: Profile details
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Profile"
        "404":
          description: Profile not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
    put:
      summary: Update a client's profile settings
      tags: [Client Profiles]
      parameters:
        - name: user_id
          in: path
          required: true
          schema:
            type: string
        - name: config_id
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                dns_preset:
                  type: string
                  enum: [no_filtering, security, family]
                safe_search:
                  type: boolean
                whitelist:
                  type: array
                  items:
                    type: string
                blacklist:
                  type: array
                  items:
                    type: string
                blocked_services:
                  type: array
                  items:
                    type: string
                blocked_services_enabled:
                  type: boolean
                linked_ips:
                  type: array
                  items:
                    type: string
      responses:
        "200":
          description: Profile updated
    delete:
      summary: Delete a client's profile
      tags: [Client Profiles]
      parameters:
        - name: user_id
          in: path
          required: true
          schema:
            type: string
        - name: config_id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Profile deleted

  /api/analytics/{config_id}/stats:
    get:
      summary: Stats overview
      tags: [Client Analytics]
      parameters:
        - name: config_id
          in: path
          required: true
          schema:
            type: string
            example: a1b2c3d4e5f6
        - name: period
          in: query
          schema:
            type: string
            enum: [24h, 7d, 30d]
            default: 24h
      responses:
        "200":
          description: Stats
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Stats"

  /api/analytics/{config_id}/queries:
    get:
      summary: Query log
      tags: [Client Analytics]
      parameters:
        - name: config_id
          in: path
          required: true
          schema:
            type: string
        - name: limit
          in: query
          schema:
            type: integer
            default: 50
        - name: offset
          in: query
          schema:
            type: integer
            default: 0
        - name: search
          in: query
          schema:
            type: string
          description: Search by domain or device name
        - name: blocked
          in: query
          schema:
            type: boolean
          description: Filter blocked queries only
      responses:
        "200":
          description: Query log entries

  /api/analytics/{config_id}/top-domains:
    get:
      summary: Top domains, blocked domains, devices
      tags: [Client Analytics]
      parameters:
        - name: config_id
          in: path
          required: true
          schema:
            type: string
        - name: limit
          in: query
          schema:
            type: integer
            default: 100
        - name: period
          in: query
          schema:
            type: string
            enum: [24h, 7d, 30d]
            default: 24h
      responses:
        "200":
          description: Top domains data

  /api/analytics/{config_id}/destinations:
    get:
      summary: Traffic destinations by country
      tags: [Client Analytics]
      parameters:
        - name: config_id
          in: path
          required: true
          schema:
            type: string
        - name: period
          in: query
          schema:
            type: string
            enum: [24h, 7d, 30d]
            default: 24h
      responses:
        "200":
          description: Destinations by country

  /api/admin/stats:
    get:
      summary: Global stats (all clients)
      tags: [System]
      parameters:
        - name: period
          in: query
          schema:
            type: string
            enum: [5m, 24h, 7d, 30d]
            default: 24h
      responses:
        "200":
          description: Global stats

  /api/admin/node-stats:
    get:
      summary: Per-node stats
      tags: [System]
      parameters:
        - name: period
          in: query
          schema:
            type: string
            enum: [5m, 24h, 7d, 30d]
            default: 24h
      responses:
        "200":
          description: Per-node stats

  /api/admin/health:
    get:
      summary: System health checks
      tags: [System]
      responses:
        "200":
          description: Health status
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    enum: [ok, warning, critical]
                  summary:
                    type: string
                  dns:
                    type: array
                    items:
                      type: object
                  infra:
                    type: array
                    items:
                      type: object
                  security:
                    type: array
                    items:
                      type: object
