{
  "openapi": "3.0.3",
  "info": {
    "title": "V7 Kassa API",
    "version": "1.0",
    "description": "Koppel-API voor de V7 Kassa: lezen (GET) en schrijven (POST: voorraad en orders, met schrijfrecht). Bedragen in hele centen. Een token hoort bij één kassa. Documentatie: https://api.v7.nl/",
    "contact": { "name": "V7 Kassa", "email": "info@tillikassa.nl", "url": "https://v7.nl" }
  },
  "servers": [ { "url": "https://api.v7.nl/v1" } ],
  "security": [ { "bearerAuth": [] } ],
  "components": {
    "securitySchemes": {
      "bearerAuth": { "type": "http", "scheme": "bearer", "description": "Token uit BEHEER → API-koppelingen. Meesturen als 'Authorization: Bearer <token>'." }
    },
    "responses": {
      "Unauthorized": { "description": "Geen of ongeldig token" },
      "RateLimited": { "description": "Te veel verzoeken (rate-limit). Zie Retry-After." }
    }
  },
  "paths": {
    "/ping": {
      "get": {
        "summary": "Health check (zonder token)",
        "security": [],
        "responses": { "200": { "description": "Service bereikbaar" } }
      }
    },
    "/kassa": {
      "get": { "summary": "Basisinfo over de kassa achter dit token",
        "responses": { "200": { "description": "Kassa-info" }, "401": { "$ref": "#/components/responses/Unauthorized" } } }
    },
    "/categorieen": {
      "get": { "summary": "Categorieën van de kassa",
        "responses": { "200": { "description": "Lijst categorieën" }, "401": { "$ref": "#/components/responses/Unauthorized" } } }
    },
    "/artikelen": {
      "get": { "summary": "Artikelen / menukaart",
        "parameters": [
          { "name": "zichtbaar", "in": "query", "schema": { "type": "integer", "enum": [0,1] }, "description": "1 = alleen zichtbare artikelen" },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 200, "maximum": 1000 } },
          { "name": "offset", "in": "query", "schema": { "type": "integer", "default": 0 } }
        ],
        "responses": { "200": { "description": "Lijst artikelen (prijsCent, plu, ean, categorieId, voorraad, kanalen)" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "429": { "$ref": "#/components/responses/RateLimited" } } }
    },
    "/voorraad": {
      "get": { "summary": "Voorraadstanden + minimum",
        "responses": { "200": { "description": "Voorraad per artikel" }, "401": { "$ref": "#/components/responses/Unauthorized" } } },
      "post": {
        "summary": "Voorraad bijwerken (schrijven; vereist schrijfrecht)",
        "description": "Body met artikelId (of ean/plu) en 'voorraad' (absoluut) of 'mutatie' (delta).",
        "requestBody": { "required": true, "content": { "application/json": { "schema": {
          "type": "object",
          "properties": {
            "artikelId": { "type": "integer" }, "ean": { "type": "string" }, "plu": { "type": "string" },
            "voorraad": { "type": "integer", "description": "absoluut zetten" },
            "mutatie": { "type": "integer", "description": "erbij/eraf" }
          } } } } },
        "responses": { "200": { "description": "Bijgewerkt" }, "403": { "description": "Geen schrijfrecht" }, "404": { "description": "Artikel niet gevonden" } }
      }
    },
    "/omzet": {
      "get": { "summary": "Omzet per dag, per btw en per betaalwijze",
        "parameters": [
          { "name": "van", "in": "query", "schema": { "type": "string", "format": "date" }, "description": "YYYY-MM-DD (standaard 30 dagen terug)" },
          { "name": "tot", "in": "query", "schema": { "type": "string", "format": "date" }, "description": "YYYY-MM-DD (standaard vandaag)" }
        ],
        "responses": { "200": { "description": "Omzetoverzicht" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "429": { "$ref": "#/components/responses/RateLimited" } } }
    },
    "/bonnen": {
      "get": { "summary": "Afgerekende bonnen (samenvatting)",
        "parameters": [
          { "name": "van", "in": "query", "schema": { "type": "string", "format": "date" } },
          { "name": "tot", "in": "query", "schema": { "type": "string", "format": "date" } },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 100, "maximum": 500 } },
          { "name": "offset", "in": "query", "schema": { "type": "integer", "default": 0 } }
        ],
        "responses": { "200": { "description": "Lijst bonnen met bonsleutel" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "429": { "$ref": "#/components/responses/RateLimited" } } }
    },
    "/bon": {
      "get": { "summary": "Eén bon met regels en betalingen",
        "parameters": [ { "name": "key", "in": "query", "required": true, "schema": { "type": "string" }, "description": "Bonsleutel uit /bonnen" } ],
        "responses": { "200": { "description": "Bon-detail" }, "404": { "description": "Bon niet gevonden" }, "401": { "$ref": "#/components/responses/Unauthorized" } } }
    },
    "/order": {
      "post": {
        "summary": "Order inschieten (schrijven; vereist schrijfrecht)",
        "description": "POST /v1/order — maakt/vult een open bon in de kassa.",
        "requestBody": { "required": true, "content": { "application/json": { "schema": {
          "type": "object", "required": ["items"],
          "properties": {
            "tafel": { "type": "string", "description": "bijv. '12', 'afhaal' of '*'" },
            "naam": { "type": "string" }, "referentie": { "type": "string" },
            "items": { "type": "array", "items": { "type": "object",
              "properties": { "artikelId": { "type": "integer" }, "aantal": { "type": "integer" } } } }
          } } } } },
        "responses": { "201": { "description": "Order aangemaakt" }, "403": { "description": "Geen schrijfrecht" }, "400": { "description": "Geen items" } }
      }
    }
  }
}
