{
  "openapi": "3.1.0",
  "info": {
    "title": "Vidhave API",
    "version": "1.0.0",
    "summary": "Öppettider, status, prislista och statistik för Vidhave på Gotland.",
    "description": "Öppna data utan inloggning för de öppna vägarna. Tider i lokal tid (Europe/Stockholm), belopp i SEK. Varje JSON-svar bär sin egen beskrivning i fältet `_readme`: parametrar, fält och tjänstekatalog. Läs den först.\n\nOpen data, no sign-in for the open paths. Local time (Europe/Stockholm), amounts in SEK. Every JSON answer describes itself in `_readme`.",
    "contact": { "name": "Vidhave", "email": "booking@vidhave.se", "url": "https://vidhave.se" }
  },
  "servers": [{ "url": "https://api.vidhave.se" }],
  "tags": [
    { "name": "Öppettider", "description": "Opening hours and open/closed status" },
    { "name": "Priser", "description": "Price list" },
    { "name": "Statistik", "description": "Booking statistics" }
  ],
  "paths": {
    "/publicSchedule": {
      "get": {
        "tags": ["Öppettider"],
        "summary": "Öppettider, priser och bokningslänkar per tjänst",
        "description": "En typisk vecka (standard) eller de faktiska kommande dagarna. Tjänsterna (bastu, badtunna, restaurangen …) listas i `_readme.catalog`.",
        "parameters": [
          { "name": "services", "in": "query", "required": true, "schema": { "type": "string" }, "example": "bastu,badtunna", "description": "Kommaseparerade slugs eller id ur `_readme.catalog`. Svaret följer samma ordning." },
          { "name": "mode", "in": "query", "schema": { "type": "string", "enum": ["week", "days"], "default": "week" }, "description": "`week` = typisk vecka, `days` = faktiska kommande dagar." },
          { "name": "days", "in": "query", "schema": { "type": "integer", "minimum": 1 }, "description": "Antal dagar vid `mode=days`." },
          { "name": "from", "in": "query", "schema": { "type": "string", "format": "date" }, "description": "Första dag vid `mode=days` (i dag till ett år fram)." },
          { "name": "prices", "in": "query", "schema": { "type": "string", "enum": ["1"] }, "description": "Lägg till prisintervall per tjänst." }
        ],
        "responses": { "200": { "description": "JSON med `_readme`, `services` och tider.", "content": { "application/json": { "schema": { "type": "object" } } } } }
      }
    },
    "/v1/status": {
      "get": {
        "tags": ["Öppettider"],
        "summary": "Har vi öppet just nu?",
        "description": "En rad per tjänst: `is_open`, `closes_at`, `next_opens_at`, `book_url`. `is_open: null` betyder att tiderna inte kunde läsas, inte stängt.",
        "parameters": [
          { "name": "service", "in": "query", "schema": { "type": "string" }, "description": "Slug eller id, kommaseparerat. Utan = alla tjänster." },
          { "name": "at", "in": "query", "schema": { "type": "string", "format": "date-time" }, "description": "Räkna för en annan tidpunkt (prov)." }
        ],
        "responses": { "200": { "description": "JSON med `services` och `_readme`.", "content": { "application/json": { "schema": { "type": "object" } } } } }
      }
    },
    "/prislista": {
      "get": {
        "tags": ["Priser"],
        "summary": "Dagens prislista",
        "description": "De priser som gäller i dag; en ändring syns här samma stund. Reglerna för hur priskomponenterna räknas ihop står i `_readme.regler`.",
        "parameters": [
          { "name": "segment", "in": "query", "schema": { "type": "string", "enum": ["privat", "foretag"] }, "description": "`foretag` = exklusive moms, `privat` = det pris kunden ser inklusive moms." },
          { "name": "eventDate", "in": "query", "schema": { "type": "string", "format": "date" }, "description": "Priserna som gäller ett visst datum." }
        ],
        "responses": { "200": { "description": "JSON med `articles`.", "content": { "application/json": { "schema": { "type": "object" } } } } }
      }
    },
    "/report/prislista": {
      "get": {
        "tags": ["Priser"],
        "summary": "Hela prislistan med historik, arkiv och interna fält",
        "security": [{ "apiKey": [] }],
        "parameters": [
          { "name": "segment", "in": "query", "schema": { "type": "string", "enum": ["privat", "foretag"] } },
          { "name": "eventDate", "in": "query", "schema": { "type": "string", "format": "date" } }
        ],
        "responses": { "200": { "description": "JSON." }, "401": { "description": "Nyckel saknas eller saknar omfånget `prislista`." } }
      }
    },
    "/statistik": {
      "get": {
        "tags": ["Statistik"],
        "summary": "Anonym bokningsstatistik utan belopp",
        "description": "En rad per husbokning med hustyp (Grand villa, Bungalow, Tiny), nätter, gäster, land och status. Inga hus, gäster eller ägare.",
        "parameters": [
          { "name": "from", "in": "query", "schema": { "type": "string", "format": "date" } },
          { "name": "to", "in": "query", "schema": { "type": "string", "format": "date" } }
        ],
        "responses": { "200": { "description": "JSON med `bookings`.", "content": { "application/json": { "schema": { "type": "object" } } } } }
      }
    },
    "/report/statistik": {
      "get": {
        "tags": ["Statistik"],
        "summary": "Statistik med belopp, produkter och källa",
        "security": [{ "apiKey": [] }],
        "parameters": [
          { "name": "from", "in": "query", "schema": { "type": "string", "format": "date" } },
          { "name": "to", "in": "query", "schema": { "type": "string", "format": "date" } }
        ],
        "responses": { "200": { "description": "JSON." }, "401": { "description": "Nyckel saknas eller saknar omfånget `statistik`." } }
      }
    },
    "/report/statistik/partner": {
      "get": {
        "tags": ["Statistik"],
        "summary": "Statistik med kallhyra, utan produkter och källa",
        "security": [{ "apiKey": [] }],
        "parameters": [
          { "name": "from", "in": "query", "schema": { "type": "string", "format": "date" } },
          { "name": "to", "in": "query", "schema": { "type": "string", "format": "date" } }
        ],
        "responses": { "200": { "description": "JSON." }, "401": { "description": "Nyckel saknas eller saknar omfånget `statistik:partner`." } }
      }
    },
    "/statistik/dygnspris": {
      "get": {
        "tags": ["Statistik"],
        "summary": "Genomsnittligt dygnspris per hustyp för en period",
        "description": "Totalpris per natt (boende + produkter), avrundat, mätt på utvalda nätter i perioden. Kallhyran följer bara med när headern `X-Statistics-Key` är rätt.",
        "parameters": [
          { "name": "period", "in": "query", "required": true, "schema": { "type": "string", "enum": ["forsasong", "sommar", "vinter"] } },
          { "name": "year", "in": "query", "required": true, "schema": { "type": "integer" }, "example": 2026 }
        ],
        "responses": { "200": { "description": "JSON per hustyp.", "content": { "application/json": { "schema": { "type": "object" } } } } }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKey": { "type": "apiKey", "in": "header", "name": "x-api-key", "description": "En nyckel per person, utfärdad av Vidhave. Nyckeln bär de omfång personen behöver." }
    }
  }
}
