{
  "openapi": "3.0.3",
  "info": {
    "title": "Floowlie Public API",
    "version": "1.1.0",
    "description": "REST API for accessing Floowlie review, employee and analytics data. See https://floowlie.se/docs/api for human-readable docs.",
    "contact": { "email": "floowlie.se@gmail.com", "url": "https://floowlie.se" }
  },
  "servers": [
    { "url": "https://api.floowlie.se/v1", "description": "Floowlie Public API (produktion)" }
  ],
  "components": {
    "securitySchemes": {
      "ApiKey": { "type": "http", "scheme": "bearer", "bearerFormat": "flw_live_*" }
    },
    "schemas": {
      "Review": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "rating": { "type": "integer", "minimum": 1, "maximum": 5 },
          "text": { "type": "string", "nullable": true },
          "reviewer_name": { "type": "string", "nullable": true },
          "created_at": { "type": "string", "format": "date-time" },
          "language": { "type": "string", "nullable": true, "example": "sv" },
          "status": { "type": "string", "example": "published" },
          "reply": { "type": "string", "nullable": true },
          "reply_published_at": { "type": "string", "format": "date-time", "nullable": true }
        }
      },
      "Error": {
        "type": "object",
        "properties": { "error": { "type": "string" } }
      }
    }
  },
  "security": [{ "ApiKey": [] }],
  "paths": {
    "/health": {
      "get": {
        "summary": "Verify API key",
        "responses": { "200": { "description": "OK" }, "401": { "description": "Unauthorized" } }
      }
    },
    "/stats": {
      "get": {
        "summary": "Company stats (totals, averages, last 30 days)",
        "responses": { "200": { "description": "OK" } }
      }
    },
    "/analytics/sentiment": {
      "get": {
        "summary": "Sentiment breakdown by rating and language",
        "responses": { "200": { "description": "OK" } }
      }
    },
    "/employees": {
      "get": {
        "summary": "List employees",
        "responses": { "200": { "description": "OK" } }
      }
    },
    "/analytics/ratings": {
      "get": {
        "summary": "Rating distribution (1–5 stars) with total and average",
        "responses": { "200": { "description": "OK" } }
      }
    },
    "/analytics/timeseries": {
      "get": {
        "summary": "Daily timeseries for scans or reviews",
        "parameters": [
          { "name": "metric", "in": "query", "schema": { "type": "string", "enum": ["scans", "reviews"] } },
          { "name": "days", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 365 } }
        ],
        "responses": { "200": { "description": "OK" } }
      }
    },
    "/analytics/top-employees": {
      "get": {
        "summary": "Top employees by scans over a period",
        "parameters": [
          { "name": "period", "in": "query", "schema": { "type": "string", "enum": ["all", "7d", "30d", "90d"] } },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 100 } }
        ],
        "responses": { "200": { "description": "OK" } }
      }
    },
    "/employees/{id}": {
      "get": {
        "summary": "Employee details with scan totals",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": { "200": { "description": "OK" }, "404": { "description": "Not found" } }
      }
    },
    "/employees/{id}/scans": {
      "get": {
        "summary": "Recent QR scans for an employee",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 500 } }
        ],
        "responses": { "200": { "description": "OK" }, "404": { "description": "Not found" } }
      }
    },
    "/scans": {
      "get": {
        "summary": "All QR scans for the company",
        "parameters": [
          { "name": "since", "in": "query", "schema": { "type": "string", "format": "date-time" } },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 500 } }
        ],
        "responses": { "200": { "description": "OK" } }
      }
    },
    "/webhooks": {
      "get": {
        "summary": "List registered webhooks for the company",
        "responses": { "200": { "description": "OK" } }
      }
    },
    "/leaderboard": {
      "get": {
        "summary": "Public employee leaderboard",
        "responses": { "200": { "description": "OK" } }
      }
    },
    "/reviews": {
      "get": {
        "summary": "List reviews",
        "parameters": [
          { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 100 } },
          { "name": "min_rating", "in": "query", "schema": { "type": "integer" } },
          { "name": "max_rating", "in": "query", "schema": { "type": "integer" } },
          { "name": "since", "in": "query", "schema": { "type": "string", "format": "date-time" } },
          { "name": "language", "in": "query", "schema": { "type": "string", "example": "sv" } }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "reviews": { "type": "array", "items": { "$ref": "#/components/schemas/Review" } }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/reviews/{id}": {
      "get": {
        "summary": "Get a single review",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "OK" },
          "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    }
  }
}