{
 "openapi": "3.0.3",
 "info": {
  "title": "EET kasa – API",
  "version": "1",
  "description": "REST rozhraní pokladny EET kasa pro napojení účetnictví, e-shopu, skladového systému nebo vlastního zálohování účtenek (modul **API**, 149 Kč měsíčně ke každému plánu, v Max Plus v ceně).\n\n**Ověření:** hlavička `Authorization: Bearer <API klíč>`; klíč vytvoříte v administraci v menu *API* (tlačítko *Authorize* vpravo nahoře ho vloží ke zkouškám). **Odpovědi:** JSON s `ok`; seznamy mají `page`, `per_page`, `has_more`. **Časy** ISO 8601 s posunem (`2026-10-14T09:15:00+02:00`), **částky** čísla v Kč s DPH. **Limity:** 120 požadavků za minutu na klíč, 20 000 za den na firmu (429 + `Retry-After`). **Změny stahujte přes `since_id`** (jen záznamy s vyšším id). Části Sklad, Zákaznické účty, Kupony a Cenové akce vyžadují zapnutý modul; zápis vyžaduje klíč s oprávněním *Čtení a zápis*. Průvodce a příklady: [návod API](/api/).",
  "contact": {
   "name": "EET kasa",
   "url": "https://eet-kasa.cz/#kontakt",
   "email": "Michal.Kunc@cloudcore.cz"
  },
  "termsOfService": "https://eet-kasa.cz/obchodni-podminky/"
 },
 "servers": [
  {
   "url": "https://pokladna.eet-kasa.cz/api/ext/v1",
   "description": "Pokladna EET kasa"
  }
 ],
 "security": [
  {
   "apiKey": []
  }
 ],
 "tags": [
  {
   "name": "Základ",
   "description": "Firma, pokladny, obsluha, sazby DPH, platební metody. Bez dalších modulů."
  },
  {
   "name": "Katalog",
   "description": "Kategorie a produkty; zápis klíčem s oprávněním Čtení a zápis."
  },
  {
   "name": "Prodeje a účtenky",
   "description": "Účtenky a storna s položkami, platbami a stavem EET; účtenka jako HTML. Jen ke čtení."
  },
  {
   "name": "Směny a reporty",
   "description": "Směny s uzávěrkou a pohyby hotovosti, souhrn tržeb za období. Jen ke čtení."
  },
  {
   "name": "Sklad",
   "description": "Modul Sklad: sklady, položky, stavy se šaržemi, pohyby; příjemky, odpisy a korekce."
  },
  {
   "name": "Zákaznické účty",
   "description": "Modul Zákaznické účty: účty s nezaplacenými položkami a historií. Jen ke čtení."
  },
  {
   "name": "Kupony",
   "description": "Modul Kupony: slevové kódy, čtení i zápis."
  },
  {
   "name": "Cenové akce",
   "description": "Modul Cenové akce: akční ceny, slevy a akce N+M, čtení i zápis."
  }
 ],
 "paths": {
  "/me": {
   "get": {
    "tags": [
     "Základ"
    ],
    "summary": "Firma, moduly, klíč a limity",
    "description": "První zkouška klíče: vrátí firmu, zapnuté moduly, údaje o použitém klíči a limity. Hodí se i k ověření, které části API jsou dostupné.",
    "responses": {
     "200": {
      "description": "Záznam.",
      "headers": {
       "X-RateLimit-Limit": {
        "description": "Limit požadavků za minutu na klíč.",
        "schema": {
         "type": "integer",
         "example": 120
        }
       },
       "X-RateLimit-Remaining": {
        "description": "Kolik požadavků v tomto okně zbývá.",
        "schema": {
         "type": "integer",
         "example": 118
        }
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean",
           "example": true
          },
          "data": {
           "$ref": "#/components/schemas/Me"
          }
         },
         "required": [
          "ok",
          "data"
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     }
    }
   }
  },
  "/registers": {
   "get": {
    "tags": [
     "Základ"
    ],
    "summary": "Pokladny",
    "description": "Všechny pokladny firmy včetně neaktivních.",
    "responses": {
     "200": {
      "description": "Záznam.",
      "headers": {
       "X-RateLimit-Limit": {
        "description": "Limit požadavků za minutu na klíč.",
        "schema": {
         "type": "integer",
         "example": 120
        }
       },
       "X-RateLimit-Remaining": {
        "description": "Kolik požadavků v tomto okně zbývá.",
        "schema": {
         "type": "integer",
         "example": 118
        }
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean",
           "example": true
          },
          "data": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/Register"
           }
          }
         },
         "required": [
          "ok",
          "data"
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     }
    }
   }
  },
  "/users": {
   "get": {
    "tags": [
     "Základ"
    ],
    "summary": "Obsluha",
    "description": "Uživatelé s PINem (vedoucí, pokladní). PIN se nevrací.",
    "responses": {
     "200": {
      "description": "Záznam.",
      "headers": {
       "X-RateLimit-Limit": {
        "description": "Limit požadavků za minutu na klíč.",
        "schema": {
         "type": "integer",
         "example": 120
        }
       },
       "X-RateLimit-Remaining": {
        "description": "Kolik požadavků v tomto okně zbývá.",
        "schema": {
         "type": "integer",
         "example": 118
        }
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean",
           "example": true
          },
          "data": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/User"
           }
          }
         },
         "required": [
          "ok",
          "data"
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     }
    }
   }
  },
  "/vat-rates": {
   "get": {
    "tags": [
     "Základ"
    ],
    "summary": "Sazby DPH",
    "description": "Sazby DPH dostupné firmě.",
    "responses": {
     "200": {
      "description": "Záznam.",
      "headers": {
       "X-RateLimit-Limit": {
        "description": "Limit požadavků za minutu na klíč.",
        "schema": {
         "type": "integer",
         "example": 120
        }
       },
       "X-RateLimit-Remaining": {
        "description": "Kolik požadavků v tomto okně zbývá.",
        "schema": {
         "type": "integer",
         "example": 118
        }
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean",
           "example": true
          },
          "data": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/VatRate"
           }
          }
         },
         "required": [
          "ok",
          "data"
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     }
    }
   }
  },
  "/payment-methods": {
   "get": {
    "tags": [
     "Základ"
    ],
    "summary": "Platební metody",
    "description": "Platební metody firmy; `code` odpovídá `method_code` na platbách dokladů.",
    "responses": {
     "200": {
      "description": "Záznam.",
      "headers": {
       "X-RateLimit-Limit": {
        "description": "Limit požadavků za minutu na klíč.",
        "schema": {
         "type": "integer",
         "example": 120
        }
       },
       "X-RateLimit-Remaining": {
        "description": "Kolik požadavků v tomto okně zbývá.",
        "schema": {
         "type": "integer",
         "example": 118
        }
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean",
           "example": true
          },
          "data": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/PaymentMethod"
           }
          }
         },
         "required": [
          "ok",
          "data"
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     }
    }
   }
  },
  "/categories": {
   "get": {
    "tags": [
     "Katalog"
    ],
    "summary": "Kategorie",
    "description": "Všechny kategorie s počtem produktů, řazené jako na pokladně.",
    "responses": {
     "200": {
      "description": "Záznam.",
      "headers": {
       "X-RateLimit-Limit": {
        "description": "Limit požadavků za minutu na klíč.",
        "schema": {
         "type": "integer",
         "example": 120
        }
       },
       "X-RateLimit-Remaining": {
        "description": "Kolik požadavků v tomto okně zbývá.",
        "schema": {
         "type": "integer",
         "example": 118
        }
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean",
           "example": true
          },
          "data": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/Category"
           }
          }
         },
         "required": [
          "ok",
          "data"
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     }
    }
   },
   "post": {
    "tags": [
     "Katalog"
    ],
    "summary": "Založit kategorii",
    "description": "Založí kategorii; pokladny si katalog stáhnou samy.\n\n**Vyžaduje klíč s oprávněním Čtení a zápis.**",
    "responses": {
     "201": {
      "description": "Založeno.",
      "headers": {
       "X-RateLimit-Limit": {
        "description": "Limit požadavků za minutu na klíč.",
        "schema": {
         "type": "integer",
         "example": 120
        }
       },
       "X-RateLimit-Remaining": {
        "description": "Kolik požadavků v tomto okně zbývá.",
        "schema": {
         "type": "integer",
         "example": 118
        }
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean",
           "example": true
          },
          "data": {
           "$ref": "#/components/schemas/Category"
          }
         },
         "required": [
          "ok",
          "data"
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "422": {
      "$ref": "#/components/responses/Validation"
     }
    },
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/CategoryInput"
       }
      }
     }
    }
   }
  },
  "/categories/{id}": {
   "patch": {
    "tags": [
     "Katalog"
    ],
    "summary": "Změnit kategorii",
    "description": "Změní jen zadaná pole.\n\n**Vyžaduje klíč s oprávněním Čtení a zápis.**",
    "responses": {
     "200": {
      "description": "Změněno.",
      "headers": {
       "X-RateLimit-Limit": {
        "description": "Limit požadavků za minutu na klíč.",
        "schema": {
         "type": "integer",
         "example": 120
        }
       },
       "X-RateLimit-Remaining": {
        "description": "Kolik požadavků v tomto okně zbývá.",
        "schema": {
         "type": "integer",
         "example": 118
        }
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean",
           "example": true
          },
          "data": {
           "$ref": "#/components/schemas/Category"
          }
         },
         "required": [
          "ok",
          "data"
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "422": {
      "$ref": "#/components/responses/Validation"
     }
    },
    "parameters": [
     {
      "$ref": "#/components/parameters/id"
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/CategoryInput"
       }
      }
     }
    }
   }
  },
  "/products": {
   "get": {
    "tags": [
     "Katalog"
    ],
    "summary": "Produkty",
    "description": "Produkty řazené podle id. `updated_since` vrátí jen produkty změněné od zadaného času (synchronizace katalogu).",
    "responses": {
     "200": {
      "description": "Seznam.",
      "headers": {
       "X-RateLimit-Limit": {
        "description": "Limit požadavků za minutu na klíč.",
        "schema": {
         "type": "integer",
         "example": 120
        }
       },
       "X-RateLimit-Remaining": {
        "description": "Kolik požadavků v tomto okně zbývá.",
        "schema": {
         "type": "integer",
         "example": 118
        }
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "allOf": [
          {
           "type": "object",
           "properties": {
            "ok": {
             "type": "boolean",
             "example": true
            },
            "data": {
             "type": "array",
             "items": {
              "$ref": "#/components/schemas/Product"
             }
            }
           },
           "required": [
            "ok",
            "data"
           ]
          },
          {
           "$ref": "#/components/schemas/ListMeta"
          }
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     }
    },
    "parameters": [
     {
      "$ref": "#/components/parameters/page"
     },
     {
      "$ref": "#/components/parameters/per_page"
     },
     {
      "$ref": "#/components/parameters/active"
     },
     {
      "name": "updated_since",
      "in": "query",
      "description": "Jen produkty změněné od času (ISO 8601).",
      "schema": {
       "type": "string",
       "format": "date-time",
       "example": "2026-10-14T00:00:00+02:00"
      }
     },
     {
      "name": "category_id",
      "in": "query",
      "description": "Jen z kategorie.",
      "schema": {
       "type": "integer"
      }
     },
     {
      "name": "q",
      "in": "query",
      "description": "Hledání v názvu, PLU a EAN.",
      "schema": {
       "type": "string",
       "example": "koláč"
      }
     }
    ]
   },
   "post": {
    "tags": [
     "Katalog"
    ],
    "summary": "Založit produkt",
    "description": "Založí produkt. Se zapnutým Skladem lze `track_stock: true` rovnou založit skladovou položku.\n\n**Vyžaduje klíč s oprávněním Čtení a zápis.**",
    "responses": {
     "201": {
      "description": "Založeno.",
      "headers": {
       "X-RateLimit-Limit": {
        "description": "Limit požadavků za minutu na klíč.",
        "schema": {
         "type": "integer",
         "example": 120
        }
       },
       "X-RateLimit-Remaining": {
        "description": "Kolik požadavků v tomto okně zbývá.",
        "schema": {
         "type": "integer",
         "example": 118
        }
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean",
           "example": true
          },
          "data": {
           "$ref": "#/components/schemas/Product"
          }
         },
         "required": [
          "ok",
          "data"
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "422": {
      "$ref": "#/components/responses/Validation"
     }
    },
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/ProductInput"
       }
      }
     }
    }
   }
  },
  "/products/{id}": {
   "get": {
    "tags": [
     "Katalog"
    ],
    "summary": "Detail produktu",
    "description": "Produkt včetně variant a modifikátorů.",
    "responses": {
     "200": {
      "description": "Záznam.",
      "headers": {
       "X-RateLimit-Limit": {
        "description": "Limit požadavků za minutu na klíč.",
        "schema": {
         "type": "integer",
         "example": 120
        }
       },
       "X-RateLimit-Remaining": {
        "description": "Kolik požadavků v tomto okně zbývá.",
        "schema": {
         "type": "integer",
         "example": 118
        }
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean",
           "example": true
          },
          "data": {
           "$ref": "#/components/schemas/Product"
          }
         },
         "required": [
          "ok",
          "data"
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    },
    "parameters": [
     {
      "$ref": "#/components/parameters/id"
     }
    ]
   },
   "patch": {
    "tags": [
     "Katalog"
    ],
    "summary": "Změnit produkt",
    "description": "Změní jen zadaná pole (např. cenu nebo `is_active`).\n\n**Vyžaduje klíč s oprávněním Čtení a zápis.**",
    "responses": {
     "200": {
      "description": "Změněno.",
      "headers": {
       "X-RateLimit-Limit": {
        "description": "Limit požadavků za minutu na klíč.",
        "schema": {
         "type": "integer",
         "example": 120
        }
       },
       "X-RateLimit-Remaining": {
        "description": "Kolik požadavků v tomto okně zbývá.",
        "schema": {
         "type": "integer",
         "example": 118
        }
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean",
           "example": true
          },
          "data": {
           "$ref": "#/components/schemas/Product"
          }
         },
         "required": [
          "ok",
          "data"
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "422": {
      "$ref": "#/components/responses/Validation"
     }
    },
    "parameters": [
     {
      "$ref": "#/components/parameters/id"
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/ProductInput"
       }
      }
     }
    }
   }
  },
  "/sales": {
   "get": {
    "tags": [
     "Prodeje a účtenky"
    ],
    "summary": "Doklady",
    "description": "Účtenky a storna podle id vzestupně (bez položek; ty jsou v detailu). Pro průběžné stahování použijte `since_id` s nejvyšším už zpracovaným id, pro období `from`/`to` podle dne vystavení. Bez filtru se vrací celá historie po stránkách.",
    "responses": {
     "200": {
      "description": "Seznam.",
      "headers": {
       "X-RateLimit-Limit": {
        "description": "Limit požadavků za minutu na klíč.",
        "schema": {
         "type": "integer",
         "example": 120
        }
       },
       "X-RateLimit-Remaining": {
        "description": "Kolik požadavků v tomto okně zbývá.",
        "schema": {
         "type": "integer",
         "example": 118
        }
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "allOf": [
          {
           "type": "object",
           "properties": {
            "ok": {
             "type": "boolean",
             "example": true
            },
            "data": {
             "type": "array",
             "items": {
              "$ref": "#/components/schemas/Sale"
             }
            }
           },
           "required": [
            "ok",
            "data"
           ]
          },
          {
           "$ref": "#/components/schemas/ListMeta"
          }
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "422": {
      "$ref": "#/components/responses/Validation"
     }
    },
    "parameters": [
     {
      "$ref": "#/components/parameters/from"
     },
     {
      "$ref": "#/components/parameters/to"
     },
     {
      "$ref": "#/components/parameters/since_id"
     },
     {
      "$ref": "#/components/parameters/order"
     },
     {
      "$ref": "#/components/parameters/page"
     },
     {
      "$ref": "#/components/parameters/per_page"
     },
     {
      "name": "register_id",
      "in": "query",
      "description": "Jen z pokladny.",
      "schema": {
       "type": "integer",
       "example": 1
      }
     },
     {
      "name": "type",
      "in": "query",
      "description": "Jen prodeje, nebo jen storna.",
      "schema": {
       "type": "string",
       "enum": [
        "sale",
        "storno"
       ]
      }
     }
    ]
   }
  },
  "/sales/{id}": {
   "get": {
    "tags": [
     "Prodeje a účtenky"
    ],
    "summary": "Detail dokladu",
    "description": "Doklad s položkami (`items`), platbami (`payments`) a fakturou (`invoice`), pokud k němu existuje.",
    "responses": {
     "200": {
      "description": "Záznam.",
      "headers": {
       "X-RateLimit-Limit": {
        "description": "Limit požadavků za minutu na klíč.",
        "schema": {
         "type": "integer",
         "example": 120
        }
       },
       "X-RateLimit-Remaining": {
        "description": "Kolik požadavků v tomto okně zbývá.",
        "schema": {
         "type": "integer",
         "example": 118
        }
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean",
           "example": true
          },
          "data": {
           "$ref": "#/components/schemas/Sale"
          }
         },
         "required": [
          "ok",
          "data"
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    },
    "parameters": [
     {
      "$ref": "#/components/parameters/id"
     }
    ]
   }
  },
  "/sales/{id}/receipt": {
   "get": {
    "tags": [
     "Prodeje a účtenky"
    ],
    "summary": "Účtenka jako HTML",
    "description": "Vrátí účtenku jako HTML stránku: úzkou (jako veřejná e‑účtenka), nebo daňový doklad na A4 (`format=a4`). K archivaci uložte HTML, nebo ho v prohlížeči vytiskněte do PDF.",
    "parameters": [
     {
      "$ref": "#/components/parameters/id"
     },
     {
      "name": "format",
      "in": "query",
      "description": "thermal = úzká účtenka, a4 = doklad na A4.",
      "schema": {
       "type": "string",
       "enum": [
        "thermal",
        "a4"
       ],
       "default": "thermal"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "HTML účtenky.",
      "headers": {
       "X-RateLimit-Limit": {
        "description": "Limit požadavků za minutu na klíč.",
        "schema": {
         "type": "integer",
         "example": 120
        }
       },
       "X-RateLimit-Remaining": {
        "description": "Kolik požadavků v tomto okně zbývá.",
        "schema": {
         "type": "integer",
         "example": 118
        }
       }
      },
      "content": {
       "text/html": {
        "schema": {
         "type": "string"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    }
   }
  },
  "/shifts": {
   "get": {
    "tags": [
     "Směny a reporty"
    ],
    "summary": "Směny",
    "description": "Směny podle id vzestupně; `from`/`to` podle otevření.",
    "responses": {
     "200": {
      "description": "Seznam.",
      "headers": {
       "X-RateLimit-Limit": {
        "description": "Limit požadavků za minutu na klíč.",
        "schema": {
         "type": "integer",
         "example": 120
        }
       },
       "X-RateLimit-Remaining": {
        "description": "Kolik požadavků v tomto okně zbývá.",
        "schema": {
         "type": "integer",
         "example": 118
        }
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "allOf": [
          {
           "type": "object",
           "properties": {
            "ok": {
             "type": "boolean",
             "example": true
            },
            "data": {
             "type": "array",
             "items": {
              "$ref": "#/components/schemas/Shift"
             }
            }
           },
           "required": [
            "ok",
            "data"
           ]
          },
          {
           "$ref": "#/components/schemas/ListMeta"
          }
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "422": {
      "$ref": "#/components/responses/Validation"
     }
    },
    "parameters": [
     {
      "$ref": "#/components/parameters/from"
     },
     {
      "$ref": "#/components/parameters/to"
     },
     {
      "$ref": "#/components/parameters/since_id"
     },
     {
      "$ref": "#/components/parameters/order"
     },
     {
      "$ref": "#/components/parameters/page"
     },
     {
      "$ref": "#/components/parameters/per_page"
     },
     {
      "name": "register_id",
      "in": "query",
      "description": "Jen z pokladny.",
      "schema": {
       "type": "integer"
      }
     },
     {
      "name": "status",
      "in": "query",
      "description": "Jen otevřené, nebo jen uzavřené.",
      "schema": {
       "type": "string",
       "enum": [
        "open",
        "closed"
       ]
      }
     }
    ]
   }
  },
  "/shifts/{id}": {
   "get": {
    "tags": [
     "Směny a reporty"
    ],
    "summary": "Detail směny",
    "description": "Směna s uzávěrkou (`report`) a vklady a výběry (`cash_movements`).",
    "responses": {
     "200": {
      "description": "Záznam.",
      "headers": {
       "X-RateLimit-Limit": {
        "description": "Limit požadavků za minutu na klíč.",
        "schema": {
         "type": "integer",
         "example": 120
        }
       },
       "X-RateLimit-Remaining": {
        "description": "Kolik požadavků v tomto okně zbývá.",
        "schema": {
         "type": "integer",
         "example": 118
        }
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean",
           "example": true
          },
          "data": {
           "$ref": "#/components/schemas/Shift"
          }
         },
         "required": [
          "ok",
          "data"
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    },
    "parameters": [
     {
      "$ref": "#/components/parameters/id"
     }
    ]
   }
  },
  "/reports/summary": {
   "get": {
    "tags": [
     "Směny a reporty"
    ],
    "summary": "Souhrn tržeb za období",
    "description": "Součty za období: dokladů, tržba, slevy, spropitné, EET; rozpad po pokladnách, platebních metodách, sazbách DPH, dnech a obsluze. Bez zadání posledních 30 dnů.",
    "responses": {
     "200": {
      "description": "Záznam.",
      "headers": {
       "X-RateLimit-Limit": {
        "description": "Limit požadavků za minutu na klíč.",
        "schema": {
         "type": "integer",
         "example": 120
        }
       },
       "X-RateLimit-Remaining": {
        "description": "Kolik požadavků v tomto okně zbývá.",
        "schema": {
         "type": "integer",
         "example": 118
        }
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean",
           "example": true
          },
          "data": {
           "$ref": "#/components/schemas/Summary"
          }
         },
         "required": [
          "ok",
          "data"
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "422": {
      "$ref": "#/components/responses/Validation"
     }
    },
    "parameters": [
     {
      "$ref": "#/components/parameters/from"
     },
     {
      "$ref": "#/components/parameters/to"
     }
    ]
   }
  },
  "/stock/warehouses": {
   "get": {
    "tags": [
     "Sklad"
    ],
    "summary": "Sklady",
    "description": "Sklady firmy. Jen se zapnutým modulem **Sklad** (jinak 403 `module_disabled`).",
    "responses": {
     "200": {
      "description": "Záznam.",
      "headers": {
       "X-RateLimit-Limit": {
        "description": "Limit požadavků za minutu na klíč.",
        "schema": {
         "type": "integer",
         "example": 120
        }
       },
       "X-RateLimit-Remaining": {
        "description": "Kolik požadavků v tomto okně zbývá.",
        "schema": {
         "type": "integer",
         "example": 118
        }
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean",
           "example": true
          },
          "data": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/Warehouse"
           }
          }
         },
         "required": [
          "ok",
          "data"
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     }
    }
   }
  },
  "/stock/items": {
   "get": {
    "tags": [
     "Sklad"
    ],
    "summary": "Skladové položky",
    "description": "Skladové položky (suroviny i sledované produkty). Jen se zapnutým modulem **Sklad** (jinak 403 `module_disabled`).",
    "responses": {
     "200": {
      "description": "Seznam.",
      "headers": {
       "X-RateLimit-Limit": {
        "description": "Limit požadavků za minutu na klíč.",
        "schema": {
         "type": "integer",
         "example": 120
        }
       },
       "X-RateLimit-Remaining": {
        "description": "Kolik požadavků v tomto okně zbývá.",
        "schema": {
         "type": "integer",
         "example": 118
        }
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "allOf": [
          {
           "type": "object",
           "properties": {
            "ok": {
             "type": "boolean",
             "example": true
            },
            "data": {
             "type": "array",
             "items": {
              "$ref": "#/components/schemas/StockItem"
             }
            }
           },
           "required": [
            "ok",
            "data"
           ]
          },
          {
           "$ref": "#/components/schemas/ListMeta"
          }
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     }
    },
    "parameters": [
     {
      "$ref": "#/components/parameters/page"
     },
     {
      "$ref": "#/components/parameters/per_page"
     },
     {
      "$ref": "#/components/parameters/active"
     }
    ]
   }
  },
  "/stock/levels": {
   "get": {
    "tags": [
     "Sklad"
    ],
    "summary": "Stavy zásob",
    "description": "Stav všech aktivních položek ve skladu se šaržemi (datum expirace a množství) a nejbližší expirací. Jen se zapnutým modulem **Sklad** (jinak 403 `module_disabled`).",
    "responses": {
     "200": {
      "description": "Záznam.",
      "headers": {
       "X-RateLimit-Limit": {
        "description": "Limit požadavků za minutu na klíč.",
        "schema": {
         "type": "integer",
         "example": 120
        }
       },
       "X-RateLimit-Remaining": {
        "description": "Kolik požadavků v tomto okně zbývá.",
        "schema": {
         "type": "integer",
         "example": 118
        }
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean",
           "example": true
          },
          "data": {
           "$ref": "#/components/schemas/StockLevels"
          }
         },
         "required": [
          "ok",
          "data"
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "422": {
      "$ref": "#/components/responses/Validation"
     }
    },
    "parameters": [
     {
      "$ref": "#/components/parameters/warehouse_id"
     }
    ]
   }
  },
  "/stock/movements": {
   "get": {
    "tags": [
     "Sklad"
    ],
    "summary": "Skladové pohyby",
    "description": "Pohyby podle id vzestupně; u prodeje odkaz na doklad. Jen se zapnutým modulem **Sklad** (jinak 403 `module_disabled`).",
    "responses": {
     "200": {
      "description": "Seznam.",
      "headers": {
       "X-RateLimit-Limit": {
        "description": "Limit požadavků za minutu na klíč.",
        "schema": {
         "type": "integer",
         "example": 120
        }
       },
       "X-RateLimit-Remaining": {
        "description": "Kolik požadavků v tomto okně zbývá.",
        "schema": {
         "type": "integer",
         "example": 118
        }
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "allOf": [
          {
           "type": "object",
           "properties": {
            "ok": {
             "type": "boolean",
             "example": true
            },
            "data": {
             "type": "array",
             "items": {
              "$ref": "#/components/schemas/Movement"
             }
            }
           },
           "required": [
            "ok",
            "data"
           ]
          },
          {
           "$ref": "#/components/schemas/ListMeta"
          }
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "422": {
      "$ref": "#/components/responses/Validation"
     }
    },
    "parameters": [
     {
      "$ref": "#/components/parameters/warehouse_id"
     },
     {
      "$ref": "#/components/parameters/from"
     },
     {
      "$ref": "#/components/parameters/to"
     },
     {
      "$ref": "#/components/parameters/since_id"
     },
     {
      "$ref": "#/components/parameters/order"
     },
     {
      "$ref": "#/components/parameters/page"
     },
     {
      "$ref": "#/components/parameters/per_page"
     },
     {
      "name": "stock_item_id",
      "in": "query",
      "description": "Jen položka.",
      "schema": {
       "type": "integer"
      }
     },
     {
      "name": "type",
      "in": "query",
      "description": "Jen typ pohybu.",
      "schema": {
       "type": "string",
       "enum": [
        "sale",
        "storno",
        "receipt",
        "writeoff",
        "adjust",
        "transfer_in",
        "transfer_out",
        "inventory",
        "account_transfer",
        "account_return",
        "tab"
       ]
      }
     }
    ]
   }
  },
  "/stock/receipts": {
   "post": {
    "tags": [
     "Sklad"
    ],
    "summary": "Příjemka",
    "description": "Příjem na sklad: víc řádků najednou, položka podle `stock_item_id`, `product_id` nebo `sku`; řádek s `expires_at` založí nebo navýší šarži. Jen se zapnutým modulem **Sklad** (jinak 403 `module_disabled`).\n\n**Vyžaduje klíč s oprávněním Čtení a zápis.**",
    "responses": {
     "201": {
      "description": "Přijato.",
      "headers": {
       "X-RateLimit-Limit": {
        "description": "Limit požadavků za minutu na klíč.",
        "schema": {
         "type": "integer",
         "example": 120
        }
       },
       "X-RateLimit-Remaining": {
        "description": "Kolik požadavků v tomto okně zbývá.",
        "schema": {
         "type": "integer",
         "example": 118
        }
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean",
           "example": true
          },
          "data": {
           "$ref": "#/components/schemas/ReceiptResult"
          }
         },
         "required": [
          "ok",
          "data"
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "422": {
      "$ref": "#/components/responses/Validation"
     }
    },
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/ReceiptInput"
       }
      }
     }
    }
   }
  },
  "/stock/writeoffs": {
   "post": {
    "tags": [
     "Sklad"
    ],
    "summary": "Odpis",
    "description": "Odpis ze skladu s důvodem; bez `batch_id` se odepisuje nejdřív nejbližší expirace (u důvodu expiry prošlé šarže). Nejvýš aktuální stav. Jen se zapnutým modulem **Sklad** (jinak 403 `module_disabled`).\n\n**Vyžaduje klíč s oprávněním Čtení a zápis.**",
    "responses": {
     "201": {
      "description": "Odepsáno.",
      "headers": {
       "X-RateLimit-Limit": {
        "description": "Limit požadavků za minutu na klíč.",
        "schema": {
         "type": "integer",
         "example": 120
        }
       },
       "X-RateLimit-Remaining": {
        "description": "Kolik požadavků v tomto okně zbývá.",
        "schema": {
         "type": "integer",
         "example": 118
        }
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean",
           "example": true
          },
          "data": {
           "$ref": "#/components/schemas/WriteoffResult"
          }
         },
         "required": [
          "ok",
          "data"
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "422": {
      "$ref": "#/components/responses/Validation"
     }
    },
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/WriteoffInput"
       }
      }
     }
    }
   }
  },
  "/stock/adjustments": {
   "post": {
    "tags": [
     "Sklad"
    ],
    "summary": "Korekce stavu",
    "description": "Ruční úprava stavu (kladná přidá, záporná odebere) s povinným důvodem. Jen se zapnutým modulem **Sklad** (jinak 403 `module_disabled`).\n\n**Vyžaduje klíč s oprávněním Čtení a zápis.**",
    "responses": {
     "201": {
      "description": "Upraveno.",
      "headers": {
       "X-RateLimit-Limit": {
        "description": "Limit požadavků za minutu na klíč.",
        "schema": {
         "type": "integer",
         "example": 120
        }
       },
       "X-RateLimit-Remaining": {
        "description": "Kolik požadavků v tomto okně zbývá.",
        "schema": {
         "type": "integer",
         "example": 118
        }
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean",
           "example": true
          },
          "data": {
           "$ref": "#/components/schemas/AdjustmentResult"
          }
         },
         "required": [
          "ok",
          "data"
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "422": {
      "$ref": "#/components/responses/Validation"
     }
    },
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/AdjustmentInput"
       }
      }
     }
    }
   }
  },
  "/customer-accounts": {
   "get": {
    "tags": [
     "Zákaznické účty"
    ],
    "summary": "Zákaznické účty",
    "description": "Účty s nezaplacenou částkou a počtem položek. Jen se zapnutým modulem **Zákaznické účty** (jinak 403 `module_disabled`). Jen ke čtení.",
    "responses": {
     "200": {
      "description": "Záznam.",
      "headers": {
       "X-RateLimit-Limit": {
        "description": "Limit požadavků za minutu na klíč.",
        "schema": {
         "type": "integer",
         "example": 120
        }
       },
       "X-RateLimit-Remaining": {
        "description": "Kolik požadavků v tomto okně zbývá.",
        "schema": {
         "type": "integer",
         "example": 118
        }
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean",
           "example": true
          },
          "data": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/Account"
           }
          }
         },
         "required": [
          "ok",
          "data"
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     }
    },
    "parameters": [
     {
      "name": "active",
      "in": "query",
      "description": "0 = včetně neaktivních účtů.",
      "schema": {
       "type": "string",
       "enum": [
        "1",
        "0"
       ],
       "default": "1"
      }
     }
    ]
   }
  },
  "/customer-accounts/{id}": {
   "get": {
    "tags": [
     "Zákaznické účty"
    ],
    "summary": "Detail účtu",
    "description": "Účet s nezaplacenými položkami (`open_items`) a historií (`history`). Jen se zapnutým modulem **Zákaznické účty** (jinak 403 `module_disabled`).",
    "responses": {
     "200": {
      "description": "Záznam.",
      "headers": {
       "X-RateLimit-Limit": {
        "description": "Limit požadavků za minutu na klíč.",
        "schema": {
         "type": "integer",
         "example": 120
        }
       },
       "X-RateLimit-Remaining": {
        "description": "Kolik požadavků v tomto okně zbývá.",
        "schema": {
         "type": "integer",
         "example": 118
        }
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean",
           "example": true
          },
          "data": {
           "$ref": "#/components/schemas/Account"
          }
         },
         "required": [
          "ok",
          "data"
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    },
    "parameters": [
     {
      "$ref": "#/components/parameters/id"
     }
    ]
   }
  },
  "/coupons": {
   "get": {
    "tags": [
     "Kupony"
    ],
    "summary": "Kupony",
    "description": "Kupony podle id. Jen se zapnutým modulem **Kupony** (jinak 403 `module_disabled`).",
    "responses": {
     "200": {
      "description": "Seznam.",
      "headers": {
       "X-RateLimit-Limit": {
        "description": "Limit požadavků za minutu na klíč.",
        "schema": {
         "type": "integer",
         "example": 120
        }
       },
       "X-RateLimit-Remaining": {
        "description": "Kolik požadavků v tomto okně zbývá.",
        "schema": {
         "type": "integer",
         "example": 118
        }
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "allOf": [
          {
           "type": "object",
           "properties": {
            "ok": {
             "type": "boolean",
             "example": true
            },
            "data": {
             "type": "array",
             "items": {
              "$ref": "#/components/schemas/Coupon"
             }
            }
           },
           "required": [
            "ok",
            "data"
           ]
          },
          {
           "$ref": "#/components/schemas/ListMeta"
          }
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     }
    },
    "parameters": [
     {
      "$ref": "#/components/parameters/page"
     },
     {
      "$ref": "#/components/parameters/per_page"
     },
     {
      "$ref": "#/components/parameters/active"
     }
    ]
   },
   "post": {
    "tags": [
     "Kupony"
    ],
    "summary": "Založit kupón",
    "description": "Založí kupón; kód musí být v rámci firmy jedinečný (jinak 409). Jen se zapnutým modulem **Kupony** (jinak 403 `module_disabled`).\n\n**Vyžaduje klíč s oprávněním Čtení a zápis.**",
    "responses": {
     "201": {
      "description": "Založeno.",
      "headers": {
       "X-RateLimit-Limit": {
        "description": "Limit požadavků za minutu na klíč.",
        "schema": {
         "type": "integer",
         "example": 120
        }
       },
       "X-RateLimit-Remaining": {
        "description": "Kolik požadavků v tomto okně zbývá.",
        "schema": {
         "type": "integer",
         "example": 118
        }
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean",
           "example": true
          },
          "data": {
           "$ref": "#/components/schemas/Coupon"
          }
         },
         "required": [
          "ok",
          "data"
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "422": {
      "$ref": "#/components/responses/Validation"
     },
     "409": {
      "description": "Kupón s tímto kódem už existuje.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    },
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/CouponInput"
       }
      }
     }
    }
   }
  },
  "/coupons/{id}": {
   "get": {
    "tags": [
     "Kupony"
    ],
    "summary": "Detail kupónu",
    "description": "Kupón s použitími na dokladech (`uses`). Jen se zapnutým modulem **Kupony** (jinak 403 `module_disabled`).",
    "responses": {
     "200": {
      "description": "Záznam.",
      "headers": {
       "X-RateLimit-Limit": {
        "description": "Limit požadavků za minutu na klíč.",
        "schema": {
         "type": "integer",
         "example": 120
        }
       },
       "X-RateLimit-Remaining": {
        "description": "Kolik požadavků v tomto okně zbývá.",
        "schema": {
         "type": "integer",
         "example": 118
        }
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean",
           "example": true
          },
          "data": {
           "$ref": "#/components/schemas/Coupon"
          }
         },
         "required": [
          "ok",
          "data"
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    },
    "parameters": [
     {
      "$ref": "#/components/parameters/id"
     }
    ]
   },
   "patch": {
    "tags": [
     "Kupony"
    ],
    "summary": "Změnit kupón",
    "description": "Změní jen zadaná pole (např. `is_active: false` kupón vypne). Jen se zapnutým modulem **Kupony** (jinak 403 `module_disabled`).\n\n**Vyžaduje klíč s oprávněním Čtení a zápis.**",
    "responses": {
     "200": {
      "description": "Změněno.",
      "headers": {
       "X-RateLimit-Limit": {
        "description": "Limit požadavků za minutu na klíč.",
        "schema": {
         "type": "integer",
         "example": 120
        }
       },
       "X-RateLimit-Remaining": {
        "description": "Kolik požadavků v tomto okně zbývá.",
        "schema": {
         "type": "integer",
         "example": 118
        }
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean",
           "example": true
          },
          "data": {
           "$ref": "#/components/schemas/Coupon"
          }
         },
         "required": [
          "ok",
          "data"
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "422": {
      "$ref": "#/components/responses/Validation"
     },
     "409": {
      "description": "Kupón s tímto kódem už existuje.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    },
    "parameters": [
     {
      "$ref": "#/components/parameters/id"
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/CouponInput"
       }
      }
     }
    }
   }
  },
  "/promotions": {
   "get": {
    "tags": [
     "Cenové akce"
    ],
    "summary": "Cenové akce",
    "description": "Akce podle id s produkty a kategoriemi, na které platí. Jen se zapnutým modulem **Cenové akce** (jinak 403 `module_disabled`).",
    "responses": {
     "200": {
      "description": "Seznam.",
      "headers": {
       "X-RateLimit-Limit": {
        "description": "Limit požadavků za minutu na klíč.",
        "schema": {
         "type": "integer",
         "example": 120
        }
       },
       "X-RateLimit-Remaining": {
        "description": "Kolik požadavků v tomto okně zbývá.",
        "schema": {
         "type": "integer",
         "example": 118
        }
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "allOf": [
          {
           "type": "object",
           "properties": {
            "ok": {
             "type": "boolean",
             "example": true
            },
            "data": {
             "type": "array",
             "items": {
              "$ref": "#/components/schemas/Promotion"
             }
            }
           },
           "required": [
            "ok",
            "data"
           ]
          },
          {
           "$ref": "#/components/schemas/ListMeta"
          }
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     }
    },
    "parameters": [
     {
      "$ref": "#/components/parameters/page"
     },
     {
      "$ref": "#/components/parameters/per_page"
     },
     {
      "$ref": "#/components/parameters/active"
     }
    ]
   },
   "post": {
    "tags": [
     "Cenové akce"
    ],
    "summary": "Založit cenovou akci",
    "description": "Založí akci; produkty a kategorie musí patřit firmě. Jen se zapnutým modulem **Cenové akce** (jinak 403 `module_disabled`).\n\n**Vyžaduje klíč s oprávněním Čtení a zápis.**",
    "responses": {
     "201": {
      "description": "Založeno.",
      "headers": {
       "X-RateLimit-Limit": {
        "description": "Limit požadavků za minutu na klíč.",
        "schema": {
         "type": "integer",
         "example": 120
        }
       },
       "X-RateLimit-Remaining": {
        "description": "Kolik požadavků v tomto okně zbývá.",
        "schema": {
         "type": "integer",
         "example": 118
        }
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean",
           "example": true
          },
          "data": {
           "$ref": "#/components/schemas/Promotion"
          }
         },
         "required": [
          "ok",
          "data"
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "422": {
      "$ref": "#/components/responses/Validation"
     }
    },
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/PromotionInput"
       }
      }
     }
    }
   }
  },
  "/promotions/{id}": {
   "get": {
    "tags": [
     "Cenové akce"
    ],
    "summary": "Detail cenové akce",
    "description": "Akce s produkty a kategoriemi. Jen se zapnutým modulem **Cenové akce** (jinak 403 `module_disabled`).",
    "responses": {
     "200": {
      "description": "Záznam.",
      "headers": {
       "X-RateLimit-Limit": {
        "description": "Limit požadavků za minutu na klíč.",
        "schema": {
         "type": "integer",
         "example": 120
        }
       },
       "X-RateLimit-Remaining": {
        "description": "Kolik požadavků v tomto okně zbývá.",
        "schema": {
         "type": "integer",
         "example": 118
        }
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean",
           "example": true
          },
          "data": {
           "$ref": "#/components/schemas/Promotion"
          }
         },
         "required": [
          "ok",
          "data"
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    },
    "parameters": [
     {
      "$ref": "#/components/parameters/id"
     }
    ]
   },
   "patch": {
    "tags": [
     "Cenové akce"
    ],
    "summary": "Změnit cenovou akci",
    "description": "Změní jen zadaná pole; `product_ids` a `category_ids` nahradí celý seznam. Jen se zapnutým modulem **Cenové akce** (jinak 403 `module_disabled`).\n\n**Vyžaduje klíč s oprávněním Čtení a zápis.**",
    "responses": {
     "200": {
      "description": "Změněno.",
      "headers": {
       "X-RateLimit-Limit": {
        "description": "Limit požadavků za minutu na klíč.",
        "schema": {
         "type": "integer",
         "example": 120
        }
       },
       "X-RateLimit-Remaining": {
        "description": "Kolik požadavků v tomto okně zbývá.",
        "schema": {
         "type": "integer",
         "example": 118
        }
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean",
           "example": true
          },
          "data": {
           "$ref": "#/components/schemas/Promotion"
          }
         },
         "required": [
          "ok",
          "data"
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "422": {
      "$ref": "#/components/responses/Validation"
     }
    },
    "parameters": [
     {
      "$ref": "#/components/parameters/id"
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/PromotionInput"
       }
      }
     }
    }
   }
  }
 },
 "components": {
  "securitySchemes": {
   "apiKey": {
    "type": "http",
    "scheme": "bearer",
    "bearerFormat": "eetk_…",
    "description": "API klíč z administrace (menu API). Zadejte samotný klíč, Swagger doplní „Bearer“."
   }
  },
  "schemas": {
   "Error": {
    "type": "object",
    "properties": {
     "ok": {
      "type": "boolean",
      "example": false
     },
     "error": {
      "type": "string",
      "description": "Text chyby pro člověka (česky).",
      "example": "Produkt nenalezen."
     },
     "code": {
      "type": "string",
      "description": "Strojový kód: invalid_key, revoked_key, module_disabled, read_only_key, not_found, method_not_allowed, invalid_json, validation, rate_limited, server_error.",
      "example": "not_found"
     },
     "errors": {
      "type": "object",
      "properties": {},
      "description": "Jen u validace (422/409): pole → zpráva.",
      "example": {
       "name": "Název je povinný."
      },
      "nullable": true
     },
     "module": {
      "type": "string",
      "description": "Jen u module_disabled: název modulu.",
      "example": "Sklad",
      "nullable": true
     },
     "retry_after": {
      "type": "integer",
      "description": "Jen u rate_limited: za kolik sekund to zkusit znovu.",
      "example": 22,
      "nullable": true
     }
    },
    "required": [
     "ok",
     "error",
     "code"
    ]
   },
   "ListMeta": {
    "type": "object",
    "properties": {
     "page": {
      "type": "integer",
      "example": 1
     },
     "per_page": {
      "type": "integer",
      "example": 50
     },
     "has_more": {
      "type": "boolean",
      "description": "true = existuje další stránka (page + 1).",
      "example": true
     }
    }
   },
   "Company": {
    "type": "object",
    "properties": {
     "id": {
      "type": "integer",
      "example": 12
     },
     "name": {
      "type": "string",
      "example": "Pekárna Na Rohu s.r.o."
     },
     "ico": {
      "type": "string",
      "example": "12345678"
     },
     "dic": {
      "type": "string",
      "example": "CZ12345678",
      "nullable": true
     },
     "legal_form": {
      "type": "string",
      "example": "s.r.o.",
      "nullable": true
     },
     "street": {
      "type": "string",
      "example": "Nádražní 5",
      "nullable": true
     },
     "city": {
      "type": "string",
      "example": "Kolín",
      "nullable": true
     },
     "zip": {
      "type": "string",
      "example": "28002",
      "nullable": true
     },
     "country": {
      "type": "string",
      "example": "CZ"
     },
     "vat_payer": {
      "type": "boolean",
      "description": "Plátce DPH; neplátce má na dokladech sazbu 0 %.",
      "example": true
     },
     "eet_environment": {
      "type": "string",
      "enum": [
       "playground",
       "production"
      ]
     },
     "eet_enabled": {
      "type": "boolean"
     }
    }
   },
   "Me": {
    "type": "object",
    "properties": {
     "company": {
      "$ref": "#/components/schemas/Company"
     },
     "modules": {
      "type": "object",
      "properties": {
       "stock": {
        "type": "boolean"
       },
       "recipes": {
        "type": "boolean"
       },
       "customer_accounts": {
        "type": "boolean"
       },
       "coupons": {
        "type": "boolean"
       },
       "promotions": {
        "type": "boolean"
       }
      },
      "description": "Zapnuté moduly (části API dostupné jen se zapnutým modulem)."
     },
     "key": {
      "type": "object",
      "properties": {
       "id": {
        "type": "integer",
        "example": 3
       },
       "name": {
        "type": "string",
        "example": "účetnictví"
       },
       "prefix": {
        "type": "string",
        "example": "eetk_7f3a9c1"
       },
       "can_write": {
        "type": "boolean",
        "description": "true = klíč smí zapisovat."
       },
       "expires_at": {
        "type": "string",
        "format": "date",
        "example": "2026-10-14",
        "description": "Platnost klíče do (včetně), null = bez omezení.",
        "nullable": true
       },
       "created_at": {
        "type": "string",
        "format": "date-time",
        "example": "2026-10-14T09:15:00+02:00",
        "description": "Čas ISO 8601 s posunem (Europe/Prague)."
       }
      }
     },
     "limits": {
      "type": "object",
      "properties": {
       "per_minute": {
        "type": "integer",
        "example": 120
       },
       "per_day": {
        "type": "integer",
        "example": 20000
       },
       "per_page_max": {
        "type": "integer",
        "example": 200
       }
      }
     },
     "server_time": {
      "type": "string",
      "format": "date-time",
      "example": "2026-10-14T09:15:00+02:00",
      "description": "Aktuální čas serveru."
     }
    }
   },
   "Register": {
    "type": "object",
    "properties": {
     "id": {
      "type": "integer",
      "example": 1
     },
     "code": {
      "type": "string",
      "example": "P1"
     },
     "name": {
      "type": "string",
      "example": "Pokladna u vchodu"
     },
     "jednotka_id": {
      "type": "integer",
      "description": "Evidenční jednotka EET.",
      "example": 1
     },
     "warehouse_id": {
      "type": "integer",
      "description": "Sklad pokladny (modul Sklad).",
      "example": 1,
      "nullable": true
     },
     "is_active": {
      "type": "boolean"
     },
     "last_receipt_number": {
      "type": "string",
      "description": "Poslední číslo účtenky (rok/pořadí).",
      "example": "2026/000412",
      "nullable": true
     }
    }
   },
   "User": {
    "type": "object",
    "properties": {
     "id": {
      "type": "integer",
      "example": 4
     },
     "name": {
      "type": "string",
      "example": "Marek Pokorný"
     },
     "role": {
      "type": "string",
      "enum": [
       "manager",
       "cashier"
      ],
      "description": "manager = vedoucí, cashier = pokladní."
     },
     "is_active": {
      "type": "boolean"
     },
     "created_at": {
      "type": "string",
      "format": "date-time",
      "example": "2026-10-14T09:15:00+02:00",
      "description": "Čas ISO 8601 s posunem (Europe/Prague).",
      "nullable": true
     }
    },
    "description": "Obsluha s PINem; PIN se nikdy nevrací."
   },
   "VatRate": {
    "type": "object",
    "properties": {
     "id": {
      "type": "integer",
      "example": 1
     },
     "label": {
      "type": "string",
      "example": "Základní 21 %"
     },
     "rate": {
      "type": "number",
      "example": 21.0
     },
     "is_default": {
      "type": "boolean"
     },
     "valid_from": {
      "type": "string",
      "format": "date",
      "example": "2026-10-14",
      "description": "Den RRRR-MM-DD.",
      "nullable": true
     },
     "valid_to": {
      "type": "string",
      "format": "date",
      "example": "2026-10-14",
      "description": "Den RRRR-MM-DD.",
      "nullable": true
     }
    }
   },
   "PaymentMethod": {
    "type": "object",
    "properties": {
     "id": {
      "type": "integer",
      "example": 1
     },
     "code": {
      "type": "string",
      "example": "cash",
      "description": "Kód metody, stejný jako method_code na platbách dokladu."
     },
     "name": {
      "type": "string",
      "example": "Hotovost"
     },
     "is_cash": {
      "type": "boolean"
     },
     "eet_eligible": {
      "type": "boolean",
      "description": "Platba se počítá do tržby pro EET."
     },
     "rounds_to_whole_czk": {
      "type": "boolean"
     },
     "opens_drawer": {
      "type": "boolean"
     },
     "sort": {
      "type": "integer",
      "example": 1
     },
     "is_active": {
      "type": "boolean"
     }
    }
   },
   "Category": {
    "type": "object",
    "properties": {
     "id": {
      "type": "integer",
      "example": 4
     },
     "name": {
      "type": "string",
      "example": "Pečivo"
     },
     "color": {
      "type": "string",
      "example": "#d97706",
      "nullable": true
     },
     "bon_station": {
      "type": "string",
      "enum": [
       "kitchen",
       "bar"
      ],
      "description": "Bonovací tiskárna (modul pro hospody).",
      "nullable": true
     },
     "sort": {
      "type": "integer",
      "example": 10
     },
     "is_active": {
      "type": "boolean"
     },
     "products_count": {
      "type": "integer",
      "example": 23,
      "nullable": true
     }
    }
   },
   "CategoryInput": {
    "type": "object",
    "properties": {
     "name": {
      "type": "string",
      "maxLength": 100,
      "example": "Pečivo"
     },
     "color": {
      "type": "string",
      "pattern": "^#[0-9a-fA-F]{6}$",
      "example": "#d97706",
      "nullable": true
     },
     "bon_station": {
      "type": "string",
      "enum": [
       "kitchen",
       "bar"
      ],
      "nullable": true
     },
     "sort": {
      "type": "integer",
      "example": 10
     },
     "is_active": {
      "type": "boolean",
      "example": true
     }
    },
    "description": "U POST je povinné name; u PATCH se mění jen zadaná pole."
   },
   "ProductOption": {
    "type": "object",
    "properties": {
     "name": {
      "type": "string",
      "example": "Velké"
     },
     "price": {
      "type": "number",
      "example": 85,
      "nullable": true
     },
     "delta": {
      "type": "number",
      "example": 10,
      "nullable": true
     }
    },
    "description": "Varianta (price = cena místo základní) nebo modifikátor (delta = příplatek). Jen ke čtení."
   },
   "ProductVariant": {
    "type": "object",
    "properties": {
     "id": {
      "type": "integer",
      "example": 1203
     },
     "size": {
      "type": "string",
      "example": "M"
     },
     "color": {
      "type": "string",
      "example": "šedá"
     },
     "label": {
      "type": "string",
      "example": "M / šedá"
     },
     "sku": {
      "type": "string",
      "example": "OAK-24-M-SEDA",
      "nullable": true
     },
     "ean": {
      "type": "string",
      "example": "2900000012034",
      "nullable": true
     },
     "price_incl_vat": {
      "type": "number",
      "format": "double",
      "example": 199.0,
      "description": "Vlastní cena varianty; null = cena produktu.",
      "nullable": true
     },
     "stock_item_id": {
      "type": "integer",
      "description": "Skladová položka varianty (modul Sklad).",
      "example": 418,
      "nullable": true
     }
    },
    "description": "Modul Textil: varianta produktu podle velikosti a barvy. Jen ke čtení; varianty se spravují v administraci."
   },
   "Product": {
    "type": "object",
    "properties": {
     "id": {
      "type": "integer",
      "example": 87
     },
     "category_id": {
      "type": "integer",
      "example": 4,
      "nullable": true
     },
     "name": {
      "type": "string",
      "example": "Koláč tvarohový"
     },
     "plu": {
      "type": "string",
      "example": "312",
      "nullable": true
     },
     "ean": {
      "type": "string",
      "example": "8594001234567",
      "nullable": true
     },
     "article": {
      "type": "string",
      "description": "Artikl / číslo modelu (modul Textil).",
      "example": "OAK-24",
      "nullable": true
     },
     "price_incl_vat": {
      "type": "number",
      "format": "double",
      "example": 199.0,
      "description": "Cena s DPH v Kč."
     },
     "price_variable": {
      "type": "boolean",
      "description": "Pokladna se při prodeji zeptá na částku."
     },
     "vat_rate": {
      "type": "number",
      "example": 12.0
     },
     "unit": {
      "type": "string",
      "example": "ks"
     },
     "qty_decimals": {
      "type": "integer",
      "minimum": 0,
      "maximum": 3,
      "example": 0
     },
     "variants": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/ProductOption"
      }
     },
     "modifiers": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/ProductOption"
      }
     },
     "is_favorite": {
      "type": "boolean"
     },
     "color": {
      "type": "string",
      "example": "#f59e0b",
      "nullable": true
     },
     "image_url": {
      "type": "string",
      "format": "uri",
      "example": "https://pokladna.eet-kasa.cz/media/products/12/87-3fa2b1c9.jpg",
      "nullable": true
     },
     "sort": {
      "type": "integer",
      "example": 5
     },
     "is_active": {
      "type": "boolean"
     },
     "stock_item_id": {
      "type": "integer",
      "description": "Skladová položka (modul Sklad, přímé sledování).",
      "example": 15,
      "nullable": true
     },
     "textile_variants": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/ProductVariant"
      },
      "description": "Modul Textil: varianty podle velikosti a barvy (prázdné pole bez modulu). Prodej varianty má na položce dokladu variant_id; zásoba se vede na skladové položce varianty."
     },
     "created_at": {
      "type": "string",
      "format": "date-time",
      "example": "2026-10-14T09:15:00+02:00",
      "description": "Čas ISO 8601 s posunem (Europe/Prague).",
      "nullable": true
     },
     "updated_at": {
      "type": "string",
      "format": "date-time",
      "example": "2026-10-14T09:15:00+02:00",
      "description": "Čas poslední změny; filtr updated_since.",
      "nullable": true
     }
    }
   },
   "ProductInput": {
    "type": "object",
    "properties": {
     "name": {
      "type": "string",
      "maxLength": 150,
      "example": "Koláč tvarohový"
     },
     "category_id": {
      "type": "integer",
      "example": 4,
      "nullable": true
     },
     "plu": {
      "type": "string",
      "maxLength": 20,
      "example": "312",
      "nullable": true
     },
     "ean": {
      "type": "string",
      "maxLength": 20,
      "example": "8594001234567",
      "nullable": true
     },
     "article": {
      "type": "string",
      "maxLength": 40,
      "description": "Artikl / číslo modelu (modul Textil).",
      "example": "OAK-24",
      "nullable": true
     },
     "price_incl_vat": {
      "type": "number",
      "format": "double",
      "example": 199.0,
      "description": "Cena s DPH v Kč (u POST povinná)."
     },
     "price_variable": {
      "type": "boolean",
      "example": false
     },
     "vat_rate": {
      "type": "number",
      "minimum": 0,
      "maximum": 100,
      "example": 12
     },
     "unit": {
      "type": "string",
      "maxLength": 10,
      "example": "ks"
     },
     "qty_decimals": {
      "type": "integer",
      "minimum": 0,
      "maximum": 3,
      "example": 0
     },
     "is_favorite": {
      "type": "boolean",
      "example": false
     },
     "color": {
      "type": "string",
      "pattern": "^#[0-9a-fA-F]{6}$",
      "example": "#f59e0b",
      "nullable": true
     },
     "sort": {
      "type": "integer",
      "example": 5
     },
     "is_active": {
      "type": "boolean",
      "example": true
     },
     "track_stock": {
      "type": "boolean",
      "description": "Jen modul Sklad: true založí (nebo aktivuje) skladovou položku k produktu; u produktu s variantami textilu zapne sledování všech variant.",
      "example": true
     }
    },
    "description": "U POST jsou povinné name a price_incl_vat; u PATCH se mění jen zadaná pole. Obrázek, varianty, modifikátory a varianty textilu (velikosti a barvy) se nastavují v administraci nebo importem."
   },
   "VatLine": {
    "type": "object",
    "properties": {
     "rate": {
      "type": "number",
      "example": 21.0
     },
     "base": {
      "type": "number",
      "format": "double",
      "example": 199.0,
      "description": "Základ daně."
     },
     "vat": {
      "type": "number",
      "format": "double",
      "example": 199.0,
      "description": "Daň."
     },
     "total": {
      "type": "number",
      "format": "double",
      "example": 199.0,
      "description": "Celkem s DPH."
     }
    }
   },
   "SaleCustomer": {
    "type": "object",
    "properties": {
     "name": {
      "type": "string",
      "example": "Novotný a syn s.r.o.",
      "nullable": true
     },
     "ico": {
      "type": "string",
      "example": "87654321",
      "nullable": true
     },
     "dic": {
      "type": "string",
      "example": "CZ87654321",
      "nullable": true
     },
     "street": {
      "type": "string",
      "nullable": true
     },
     "city": {
      "type": "string",
      "nullable": true
     },
     "zip": {
      "type": "string",
      "nullable": true
     },
     "country": {
      "type": "string",
      "example": "CZ",
      "nullable": true
     },
     "email": {
      "type": "string",
      "format": "email",
      "nullable": true
     }
    }
   },
   "SaleItem": {
    "type": "object",
    "properties": {
     "id": {
      "type": "integer",
      "example": 501
     },
     "product_id": {
      "type": "integer",
      "example": 87,
      "nullable": true
     },
     "name": {
      "type": "string",
      "example": "Koláč tvarohový"
     },
     "variant": {
      "type": "string",
      "example": "Velký",
      "nullable": true
     },
     "variant_id": {
      "type": "integer",
      "description": "Modul Textil: id varianty (velikost / barva).",
      "example": 1203,
      "nullable": true
     },
     "modifiers": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/ProductOption"
      }
     },
     "qty": {
      "type": "number",
      "format": "double",
      "example": 2.0,
      "description": "Množství (3 desetinná místa)."
     },
     "unit": {
      "type": "string",
      "example": "ks"
     },
     "unit_price_incl_vat": {
      "type": "number",
      "format": "double",
      "example": 199.0,
      "description": "Jednotková cena s DPH (po uplatnění akce)."
     },
     "vat_rate": {
      "type": "number",
      "example": 12.0
     },
     "discount": {
      "type": "number",
      "format": "double",
      "example": 199.0,
      "description": "Sleva na řádku v Kč."
     },
     "loyalty_discount": {
      "type": "number",
      "format": "double",
      "example": 199.0,
      "description": "Sleva věrnostní karty.",
      "nullable": true
     },
     "line_total": {
      "type": "number",
      "format": "double",
      "example": 199.0,
      "description": "Celkem za řádek po slevách."
     },
     "is_manual": {
      "type": "boolean",
      "description": "Ruční položka bez produktu."
     },
     "promotion_id": {
      "type": "integer",
      "nullable": true
     },
     "promotion_name": {
      "type": "string",
      "example": "Happy hour",
      "nullable": true
     },
     "list_unit_price": {
      "type": "number",
      "format": "double",
      "example": 199.0,
      "description": "Původní cena před akcí.",
      "nullable": true
     },
     "refunded_qty": {
      "type": "number",
      "format": "double",
      "example": 2.0,
      "description": "Množství vrácené stornem."
     }
    }
   },
   "SalePayment": {
    "type": "object",
    "properties": {
     "payment_method_id": {
      "type": "integer",
      "example": 1,
      "nullable": true
     },
     "method_code": {
      "type": "string",
      "example": "cash"
     },
     "method_name": {
      "type": "string",
      "example": "Hotovost",
      "nullable": true
     },
     "amount": {
      "type": "number",
      "format": "double",
      "example": 199.0,
      "description": "Částka v Kč s DPH."
     },
     "eet_eligible": {
      "type": "boolean"
     },
     "terminal_provider": {
      "type": "string",
      "example": "sumup",
      "nullable": true
     },
     "terminal_ref": {
      "type": "string",
      "description": "Číslo transakce terminálu.",
      "example": "TX8K2M",
      "nullable": true
     }
    }
   },
   "Sale": {
    "type": "object",
    "properties": {
     "id": {
      "type": "integer",
      "example": 1431
     },
     "receipt_number": {
      "type": "string",
      "example": "2026/000412"
     },
     "receipt_number_printed": {
      "type": "string",
      "description": "Číslo vytištěné na dokladu, liší-li se.",
      "nullable": true
     },
     "type": {
      "type": "string",
      "enum": [
       "sale",
       "storno"
      ]
     },
     "storno_of_sale_id": {
      "type": "integer",
      "description": "U storna id původního dokladu.",
      "nullable": true
     },
     "issued_at": {
      "type": "string",
      "format": "date-time",
      "example": "2026-10-14T09:15:00+02:00",
      "description": "Čas vystavení."
     },
     "register_id": {
      "type": "integer",
      "example": 1
     },
     "register_name": {
      "type": "string",
      "example": "Pokladna u vchodu",
      "nullable": true
     },
     "shift_id": {
      "type": "integer",
      "example": 58,
      "nullable": true
     },
     "user_id": {
      "type": "integer",
      "example": 4,
      "nullable": true
     },
     "user_name": {
      "type": "string",
      "example": "Marek Pokorný",
      "nullable": true
     },
     "subtotal": {
      "type": "number",
      "format": "double",
      "example": 199.0,
      "description": "Součet položek před slevou na doklad."
     },
     "discount_total": {
      "type": "number",
      "format": "double",
      "example": 199.0,
      "description": "Slevy celkem."
     },
     "rounding": {
      "type": "number",
      "format": "double",
      "example": 199.0,
      "description": "Zaokrouhlení."
     },
     "tip": {
      "type": "number",
      "format": "double",
      "example": 199.0,
      "description": "Spropitné."
     },
     "total": {
      "type": "number",
      "format": "double",
      "example": 199.0,
      "description": "Celkem k úhradě (u storna záporné)."
     },
     "eet_amount": {
      "type": "number",
      "format": "double",
      "example": 199.0,
      "description": "Tržba pro EET."
     },
     "vat_summary": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/VatLine"
      }
     },
     "customer": {
      "$ref": "#/components/schemas/SaleCustomer",
      "nullable": true
     },
     "customer_account_id": {
      "type": "integer",
      "description": "Zákaznický účet, byl-li doklad úhradou účtu.",
      "nullable": true
     },
     "reservation_id": {
      "type": "integer",
      "nullable": true
     },
     "coupon": {
      "type": "object",
      "properties": {
       "id": {
        "type": "integer",
        "nullable": true
       },
       "code": {
        "type": "string",
        "example": "PODZIM50"
       },
       "amount": {
        "type": "number",
        "format": "double",
        "example": 199.0,
        "description": "Sleva kupónu."
       }
      },
      "nullable": true
     },
     "loyalty": {
      "type": "object",
      "properties": {
       "card_code": {
        "type": "string",
        "example": "VK7Q2M8A1B"
       },
       "points_earned": {
        "type": "integer",
        "nullable": true
       },
       "points_redeemed": {
        "type": "integer",
        "nullable": true
       },
       "points_balance": {
        "type": "integer",
        "nullable": true
       },
       "reward_name": {
        "type": "string",
        "nullable": true
       },
       "discount": {
        "type": "number",
        "format": "double",
        "example": 199.0,
        "description": "Částka v Kč s DPH.",
        "nullable": true
       }
      },
      "description": "Věrnostní karta (modul Zákaznická aplikace).",
      "nullable": true
     },
     "note": {
      "type": "string",
      "nullable": true
     },
     "auth_mode": {
      "type": "string",
      "enum": [
       "online",
       "offline"
      ],
      "description": "offline = doklad vznikl bez spojení a dorazil při synchronizaci."
     },
     "eet": {
      "type": "object",
      "properties": {
       "state": {
        "type": "string",
        "enum": [
         "not_required",
         "pending",
         "sent",
         "failed"
        ]
       },
       "pok": {
        "type": "string",
        "description": "Potvrzovací kód EET (POK).",
        "example": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
        "nullable": true
       },
       "test": {
        "type": "boolean",
        "description": "Doklad z testovacího prostředí EET."
       }
      }
     },
     "receipt_url": {
      "type": "string",
      "format": "uri",
      "description": "Veřejná e‑účtenka.",
      "example": "https://pokladna.eet-kasa.cz/r/k3J9xQ2mP0aL"
     },
     "created_at": {
      "type": "string",
      "format": "date-time",
      "example": "2026-10-14T09:15:00+02:00",
      "description": "Čas uložení na server."
     },
     "synced_at": {
      "type": "string",
      "format": "date-time",
      "example": "2026-10-14T09:15:00+02:00",
      "description": "Čas ISO 8601 s posunem (Europe/Prague).",
      "nullable": true
     },
     "items": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/SaleItem"
      },
      "description": "Jen v detailu."
     },
     "payments": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/SalePayment"
      },
      "description": "Jen v detailu."
     },
     "invoice": {
      "type": "object",
      "properties": {
       "number": {
        "type": "string",
        "example": "FV202600142"
       },
       "url": {
        "type": "string",
        "format": "uri"
       }
      },
      "description": "Jen v detailu: faktura k dokladu (modul Faktury), jinak null.",
      "nullable": true
     }
    }
   },
   "CashMovement": {
    "type": "object",
    "properties": {
     "id": {
      "type": "integer",
      "example": 9
     },
     "type": {
      "type": "string",
      "enum": [
       "in",
       "out"
      ],
      "description": "in = vklad, out = výběr."
     },
     "amount": {
      "type": "number",
      "format": "double",
      "example": 199.0,
      "description": "Částka v Kč s DPH."
     },
     "reason": {
      "type": "string",
      "example": "odvod tržby",
      "nullable": true
     },
     "user_id": {
      "type": "integer",
      "nullable": true
     },
     "created_at": {
      "type": "string",
      "format": "date-time",
      "example": "2026-10-14T09:15:00+02:00",
      "description": "Čas ISO 8601 s posunem (Europe/Prague)."
     }
    }
   },
   "Shift": {
    "type": "object",
    "properties": {
     "id": {
      "type": "integer",
      "example": 58
     },
     "register_id": {
      "type": "integer",
      "example": 1
     },
     "register_name": {
      "type": "string",
      "nullable": true
     },
     "opened_by": {
      "type": "integer",
      "description": "Obsluha, která směnu otevřela.",
      "nullable": true
     },
     "opened_at": {
      "type": "string",
      "format": "date-time",
      "example": "2026-10-14T09:15:00+02:00",
      "description": "Čas ISO 8601 s posunem (Europe/Prague)."
     },
     "opening_cash": {
      "type": "number",
      "format": "double",
      "example": 199.0,
      "description": "Počáteční hotovost."
     },
     "closed_by": {
      "type": "integer",
      "nullable": true
     },
     "closed_at": {
      "type": "string",
      "format": "date-time",
      "example": "2026-10-14T09:15:00+02:00",
      "description": "Čas ISO 8601 s posunem (Europe/Prague).",
      "nullable": true
     },
     "counted_cash": {
      "type": "number",
      "format": "double",
      "example": 199.0,
      "description": "Napočítaná hotovost při uzávěrce.",
      "nullable": true
     },
     "expected_cash": {
      "type": "number",
      "format": "double",
      "example": 199.0,
      "description": "Očekávaná hotovost.",
      "nullable": true
     },
     "difference": {
      "type": "number",
      "format": "double",
      "example": 199.0,
      "description": "Rozdíl napočítané a očekávané.",
      "nullable": true
     },
     "z_number": {
      "type": "integer",
      "description": "Číslo Z‑uzávěrky.",
      "example": 57,
      "nullable": true
     },
     "sales_count": {
      "type": "integer",
      "example": 84,
      "nullable": true
     },
     "sales_total": {
      "type": "number",
      "format": "double",
      "example": 199.0,
      "description": "Částka v Kč s DPH.",
      "nullable": true
     },
     "report": {
      "type": "object",
      "properties": {},
      "description": "Jen v detailu: uzávěrka tak, jak ji pokladna uzavřela (tržby, platební metody, DPH).",
      "nullable": true
     },
     "cash_movements": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/CashMovement"
      },
      "description": "Jen v detailu."
     }
    }
   },
   "Summary": {
    "type": "object",
    "properties": {
     "from": {
      "type": "string",
      "format": "date",
      "example": "2026-10-14",
      "description": "Den RRRR-MM-DD."
     },
     "to": {
      "type": "string",
      "format": "date",
      "example": "2026-10-14",
      "description": "Den RRRR-MM-DD."
     },
     "totals": {
      "type": "object",
      "properties": {
       "documents": {
        "type": "integer",
        "example": 312
       },
       "sales": {
        "type": "integer",
        "example": 308
       },
       "stornos": {
        "type": "integer",
        "example": 4
       },
       "total": {
        "type": "number",
        "format": "double",
        "example": 199.0,
        "description": "Částka v Kč s DPH."
       },
       "discounts": {
        "type": "number",
        "format": "double",
        "example": 199.0,
        "description": "Částka v Kč s DPH."
       },
       "tips": {
        "type": "number",
        "format": "double",
        "example": 199.0,
        "description": "Částka v Kč s DPH."
       },
       "eet_amount": {
        "type": "number",
        "format": "double",
        "example": 199.0,
        "description": "Částka v Kč s DPH."
       },
       "eet_sent": {
        "type": "integer"
       },
       "eet_pending": {
        "type": "integer"
       },
       "eet_failed": {
        "type": "integer"
       }
      }
     },
     "by_register": {
      "type": "array",
      "items": {
       "type": "object",
       "properties": {
        "register_id": {
         "type": "integer"
        },
        "name": {
         "type": "string"
        },
        "documents": {
         "type": "integer"
        },
        "total": {
         "type": "number",
         "format": "double",
         "example": 199.0,
         "description": "Částka v Kč s DPH."
        },
        "storno_total": {
         "type": "number",
         "format": "double",
         "example": 199.0,
         "description": "Částka v Kč s DPH."
        }
       }
      }
     },
     "by_payment_method": {
      "type": "array",
      "items": {
       "type": "object",
       "properties": {
        "code": {
         "type": "string",
         "example": "card"
        },
        "name": {
         "type": "string",
         "example": "Platební karta"
        },
        "documents": {
         "type": "integer"
        },
        "total": {
         "type": "number",
         "format": "double",
         "example": 199.0,
         "description": "Částka v Kč s DPH."
        }
       }
      }
     },
     "by_vat": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/VatLine"
      }
     },
     "by_day": {
      "type": "array",
      "items": {
       "type": "object",
       "properties": {
        "day": {
         "type": "string",
         "format": "date",
         "example": "2026-10-14",
         "description": "Den RRRR-MM-DD."
        },
        "documents": {
         "type": "integer"
        },
        "total": {
         "type": "number",
         "format": "double",
         "example": 199.0,
         "description": "Částka v Kč s DPH."
        }
       }
      }
     },
     "by_user": {
      "type": "array",
      "items": {
       "type": "object",
       "properties": {
        "name": {
         "type": "string"
        },
        "documents": {
         "type": "integer"
        },
        "total": {
         "type": "number",
         "format": "double",
         "example": 199.0,
         "description": "Částka v Kč s DPH."
        }
       }
      }
     }
    }
   },
   "Warehouse": {
    "type": "object",
    "properties": {
     "id": {
      "type": "integer",
      "example": 1
     },
     "name": {
      "type": "string",
      "example": "Hlavní sklad"
     },
     "is_default": {
      "type": "boolean"
     },
     "is_active": {
      "type": "boolean"
     }
    }
   },
   "StockItem": {
    "type": "object",
    "properties": {
     "id": {
      "type": "integer",
      "example": 15
     },
     "product_id": {
      "type": "integer",
      "example": 87,
      "nullable": true
     },
     "variant_id": {
      "type": "integer",
      "description": "Modul Textil: položka varianty (product_id je pak null).",
      "example": 1203,
      "nullable": true
     },
     "product_name": {
      "type": "string",
      "example": "Koláč tvarohový",
      "nullable": true
     },
     "name": {
      "type": "string",
      "example": "Koláč tvarohový"
     },
     "sku": {
      "type": "string",
      "example": "KOL-TV",
      "nullable": true
     },
     "unit": {
      "type": "string",
      "example": "ks"
     },
     "qty_decimals": {
      "type": "integer",
      "example": 0
     },
     "min_qty": {
      "type": "number",
      "format": "double",
      "example": 2.0,
      "description": "Minimální zásoba.",
      "nullable": true
     },
     "purchase_price": {
      "type": "number",
      "format": "double",
      "example": 199.0,
      "description": "Nákupní cena.",
      "nullable": true
     },
     "allow_negative": {
      "type": "boolean"
     },
     "is_active": {
      "type": "boolean"
     },
     "created_at": {
      "type": "string",
      "format": "date-time",
      "example": "2026-10-14T09:15:00+02:00",
      "description": "Čas ISO 8601 s posunem (Europe/Prague).",
      "nullable": true
     }
    }
   },
   "Batch": {
    "type": "object",
    "properties": {
     "id": {
      "type": "integer",
      "example": 301
     },
     "expires_at": {
      "type": "string",
      "format": "date",
      "example": "2026-10-14",
      "description": "Datum expirace; null = šarže bez data.",
      "nullable": true
     },
     "qty": {
      "type": "number",
      "format": "double",
      "example": 2.0,
      "description": "Množství (3 desetinná místa)."
     }
    }
   },
   "StockLevel": {
    "allOf": [
     {
      "$ref": "#/components/schemas/StockItem"
     },
     {
      "type": "object",
      "properties": {
       "qty": {
        "type": "number",
        "format": "double",
        "example": 2.0,
        "description": "Stav ve skladu."
       },
       "batches": {
        "type": "array",
        "items": {
         "$ref": "#/components/schemas/Batch"
        }
       },
       "nearest_expiry": {
        "type": "string",
        "format": "date",
        "example": "2026-10-14",
        "description": "Nejbližší expirace.",
        "nullable": true
       }
      }
     }
    ]
   },
   "StockLevels": {
    "type": "object",
    "properties": {
     "warehouse_id": {
      "type": "integer",
      "example": 1
     },
     "items": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/StockLevel"
      }
     }
    }
   },
   "Movement": {
    "type": "object",
    "properties": {
     "id": {
      "type": "integer",
      "example": 9120
     },
     "warehouse_id": {
      "type": "integer",
      "example": 1
     },
     "stock_item_id": {
      "type": "integer",
      "example": 15
     },
     "item_name": {
      "type": "string",
      "nullable": true
     },
     "type": {
      "type": "string",
      "enum": [
       "sale",
       "storno",
       "receipt",
       "writeoff",
       "adjust",
       "transfer_in",
       "transfer_out",
       "inventory",
       "account_transfer",
       "account_return",
       "tab"
      ]
     },
     "qty": {
      "type": "number",
      "format": "double",
      "example": 2.0,
      "description": "Kladné = příjem, záporné = výdej."
     },
     "unit": {
      "type": "string",
      "nullable": true
     },
     "sale_id": {
      "type": "integer",
      "nullable": true
     },
     "receipt_number": {
      "type": "string",
      "nullable": true
     },
     "stock_take_id": {
      "type": "integer",
      "description": "Inventura.",
      "nullable": true
     },
     "transfer_uuid": {
      "type": "string",
      "nullable": true
     },
     "note": {
      "type": "string",
      "nullable": true
     },
     "reason": {
      "type": "string",
      "description": "Důvod odpisu.",
      "nullable": true
     },
     "unit_cost": {
      "type": "number",
      "format": "double",
      "example": 199.0,
      "description": "Nákupní cena v době pohybu.",
      "nullable": true
     },
     "expires_at": {
      "type": "string",
      "format": "date",
      "example": "2026-10-14",
      "description": "Den RRRR-MM-DD.",
      "nullable": true
     },
     "actor": {
      "type": "string",
      "enum": [
       "admin",
       "device",
       "system",
       "api"
      ],
      "description": "Kdo pohyb provedl."
     },
     "created_at": {
      "type": "string",
      "format": "date-time",
      "example": "2026-10-14T09:15:00+02:00",
      "description": "Čas ISO 8601 s posunem (Europe/Prague)."
     }
    }
   },
   "ItemRef": {
    "type": "object",
    "properties": {
     "stock_item_id": {
      "type": "integer",
      "example": 15
     },
     "product_id": {
      "type": "integer",
      "example": 87
     },
     "variant_id": {
      "type": "integer",
      "description": "Modul Textil: varianta sledovaná na skladě.",
      "example": 1203
     },
     "sku": {
      "type": "string",
      "example": "KOL-TV"
     }
    },
    "description": "Určení skladové položky jedním z polí: stock_item_id, product_id (produkt sledovaný na skladě), variant_id (varianta textilu), nebo sku."
   },
   "ReceiptInput": {
    "type": "object",
    "properties": {
     "warehouse_id": {
      "type": "integer",
      "description": "Bez zadání výchozí sklad.",
      "example": 1
     },
     "note": {
      "type": "string",
      "maxLength": 255,
      "example": "Dodávka 14. 10., DL 2026/118",
      "nullable": true
     },
     "lines": {
      "type": "array",
      "items": {
       "allOf": [
        {
         "$ref": "#/components/schemas/ItemRef"
        },
        {
         "type": "object",
         "properties": {
          "qty": {
           "type": "number",
           "format": "double",
           "example": 2.0,
           "description": "Přijaté množství (kladné)."
          },
          "expires_at": {
           "type": "string",
           "format": "date",
           "example": "2026-10-14",
           "description": "Datum expirace; řádek s datem založí nebo navýší šarži.",
           "nullable": true
          }
         },
         "required": [
          "qty"
         ]
        }
       ]
      },
      "description": "Nejvýš 200 řádků."
     }
    },
    "required": [
     "lines"
    ],
    "example": {
     "note": "Dodávka 14. 10.",
     "lines": [
      {
       "sku": "MOUKA-25",
       "qty": 50
      },
      {
       "product_id": 87,
       "qty": 12,
       "expires_at": "2026-10-20"
      }
     ]
    }
   },
   "ReceiptResult": {
    "type": "object",
    "properties": {
     "warehouse_id": {
      "type": "integer"
     },
     "lines": {
      "type": "integer",
      "description": "Počet zapsaných řádků."
     },
     "levels": {
      "type": "array",
      "items": {
       "type": "object",
       "properties": {
        "stock_item_id": {
         "type": "integer"
        },
        "name": {
         "type": "string"
        },
        "qty": {
         "type": "number",
         "format": "double",
         "example": 2.0,
         "description": "Množství (3 desetinná místa)."
        },
        "batches": {
         "type": "array",
         "items": {
          "$ref": "#/components/schemas/Batch"
         }
        }
       }
      },
      "description": "Nový stav dotčených položek."
     }
    }
   },
   "WriteoffInput": {
    "allOf": [
     {
      "$ref": "#/components/schemas/ItemRef"
     },
     {
      "type": "object",
      "properties": {
       "warehouse_id": {
        "type": "integer",
        "example": 1
       },
       "qty": {
        "type": "number",
        "format": "double",
        "example": 2.0,
        "description": "Odepsané množství (kladné, nejvýš aktuální stav)."
       },
       "reason": {
        "type": "string",
        "enum": [
         "expiry",
         "damage",
         "consumption",
         "theft",
         "other"
        ],
        "description": "expiry = expirace, damage = poškození, consumption = spotřeba provozu, theft = krádež nebo ztráta, other = jiné."
       },
       "note": {
        "type": "string",
        "maxLength": 255,
        "nullable": true
       },
       "batch_id": {
        "type": "integer",
        "description": "Jen z dané šarže; bez zadání nejdřív nejbližší expirace (u expirace prošlé šarže).",
        "nullable": true
       }
      },
      "required": [
       "qty",
       "reason"
      ]
     }
    ],
    "example": {
     "stock_item_id": 15,
     "qty": 3,
     "reason": "expiry",
     "note": "prošlé"
    }
   },
   "WriteoffResult": {
    "type": "object",
    "properties": {
     "warehouse_id": {
      "type": "integer"
     },
     "stock_item_id": {
      "type": "integer"
     },
     "qty": {
      "type": "number",
      "format": "double",
      "example": 2.0,
      "description": "Odepsáno."
     },
     "value": {
      "type": "number",
      "format": "double",
      "example": 199.0,
      "description": "Hodnota odpisu v nákupních cenách.",
      "nullable": true
     },
     "level": {
      "type": "number",
      "format": "double",
      "example": 2.0,
      "description": "Nový stav."
     }
    }
   },
   "AdjustmentInput": {
    "allOf": [
     {
      "$ref": "#/components/schemas/ItemRef"
     },
     {
      "type": "object",
      "properties": {
       "warehouse_id": {
        "type": "integer",
        "example": 1
       },
       "delta": {
        "type": "number",
        "format": "double",
        "example": 2.0,
        "description": "Změna množství: kladná přidá, záporná odebere."
       },
       "note": {
        "type": "string",
        "maxLength": 255,
        "description": "Důvod korekce (povinný).",
        "example": "doplnění po inventuře"
       },
       "expires_at": {
        "type": "string",
        "format": "date",
        "example": "2026-10-14",
        "description": "U přidání: šarže s tímto datem.",
        "nullable": true
       }
      },
      "required": [
       "delta",
       "note"
      ]
     }
    ],
    "example": {
     "product_id": 87,
     "delta": -2,
     "note": "rozbité při vybalování"
    }
   },
   "AdjustmentResult": {
    "type": "object",
    "properties": {
     "warehouse_id": {
      "type": "integer"
     },
     "stock_item_id": {
      "type": "integer"
     },
     "levels": {
      "type": "array",
      "items": {
       "type": "object",
       "properties": {
        "stock_item_id": {
         "type": "integer"
        },
        "name": {
         "type": "string"
        },
        "qty": {
         "type": "number",
         "format": "double",
         "example": 2.0,
         "description": "Množství (3 desetinná místa)."
        },
        "batches": {
         "type": "array",
         "items": {
          "$ref": "#/components/schemas/Batch"
         }
        }
       }
      }
     }
    }
   },
   "AccountItem": {
    "type": "object",
    "properties": {
     "id": {
      "type": "integer",
      "example": 77
     },
     "product_id": {
      "type": "integer",
      "nullable": true
     },
     "name": {
      "type": "string",
      "example": "Oběd dne"
     },
     "variant": {
      "type": "string",
      "nullable": true
     },
     "qty": {
      "type": "number",
      "format": "double",
      "example": 2.0,
      "description": "Množství (3 desetinná místa)."
     },
     "unit": {
      "type": "string",
      "example": "ks"
     },
     "unit_price_incl_vat": {
      "type": "number",
      "format": "double",
      "example": 199.0,
      "description": "Částka v Kč s DPH."
     },
     "vat_rate": {
      "type": "number",
      "example": 12.0
     },
     "line_total": {
      "type": "number",
      "format": "double",
      "example": 199.0,
      "description": "Částka v Kč s DPH."
     },
     "status": {
      "type": "string",
      "enum": [
       "open",
       "paid",
       "removed"
      ]
     },
     "register_id": {
      "type": "integer",
      "nullable": true
     },
     "user_name": {
      "type": "string",
      "nullable": true
     },
     "note": {
      "type": "string",
      "nullable": true
     },
     "paid_sale_id": {
      "type": "integer",
      "nullable": true
     },
     "paid_receipt_number": {
      "type": "string",
      "nullable": true
     },
     "paid_at": {
      "type": "string",
      "format": "date-time",
      "example": "2026-10-14T09:15:00+02:00",
      "description": "Čas ISO 8601 s posunem (Europe/Prague).",
      "nullable": true
     },
     "added_at": {
      "type": "string",
      "format": "date-time",
      "example": "2026-10-14T09:15:00+02:00",
      "description": "Čas ISO 8601 s posunem (Europe/Prague)."
     }
    }
   },
   "Account": {
    "type": "object",
    "properties": {
     "id": {
      "type": "integer",
      "example": 3
     },
     "name": {
      "type": "string",
      "example": "Stavební firma Holub"
     },
     "note": {
      "type": "string",
      "example": "platí fakturou koncem měsíce",
      "nullable": true
     },
     "customer_email": {
      "type": "string",
      "format": "email",
      "nullable": true
     },
     "is_active": {
      "type": "boolean"
     },
     "open_total": {
      "type": "number",
      "format": "double",
      "example": 199.0,
      "description": "Nezaplaceno celkem."
     },
     "open_count": {
      "type": "integer",
      "description": "Počet nezaplacených položek."
     },
     "last_added_at": {
      "type": "string",
      "format": "date-time",
      "example": "2026-10-14T09:15:00+02:00",
      "description": "Čas ISO 8601 s posunem (Europe/Prague).",
      "nullable": true
     },
     "created_at": {
      "type": "string",
      "format": "date-time",
      "example": "2026-10-14T09:15:00+02:00",
      "description": "Čas ISO 8601 s posunem (Europe/Prague).",
      "nullable": true
     },
     "open_items": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/AccountItem"
      },
      "description": "Jen v detailu: nezaplacené položky."
     },
     "history": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/AccountItem"
      },
      "description": "Jen v detailu: zaplacené a odebrané položky (nejvýš 300)."
     }
    }
   },
   "CouponUse": {
    "type": "object",
    "properties": {
     "sale_id": {
      "type": "integer"
     },
     "receipt_number": {
      "type": "string",
      "nullable": true
     },
     "amount": {
      "type": "number",
      "format": "double",
      "example": 199.0,
      "description": "Poskytnutá sleva."
     },
     "reversed_sale_id": {
      "type": "integer",
      "description": "Storno, které použití vrátilo.",
      "nullable": true
     },
     "used_at": {
      "type": "string",
      "format": "date-time",
      "example": "2026-10-14T09:15:00+02:00",
      "description": "Čas ISO 8601 s posunem (Europe/Prague)."
     }
    }
   },
   "Coupon": {
    "type": "object",
    "properties": {
     "id": {
      "type": "integer",
      "example": 2
     },
     "code": {
      "type": "string",
      "example": "PODZIM50"
     },
     "name": {
      "type": "string",
      "example": "Podzimní leták"
     },
     "type": {
      "type": "string",
      "enum": [
       "amount",
       "percent"
      ]
     },
     "value": {
      "type": "number",
      "example": 50
     },
     "min_total": {
      "type": "number",
      "format": "double",
      "example": 199.0,
      "description": "Minimální nákup.",
      "nullable": true
     },
     "max_uses": {
      "type": "integer",
      "description": "Nejvyšší počet použití; null = bez limitu.",
      "nullable": true
     },
     "used_count": {
      "type": "integer"
     },
     "valid_from": {
      "type": "string",
      "format": "date",
      "example": "2026-10-14",
      "description": "Den RRRR-MM-DD.",
      "nullable": true
     },
     "valid_to": {
      "type": "string",
      "format": "date",
      "example": "2026-10-14",
      "description": "Den RRRR-MM-DD.",
      "nullable": true
     },
     "note": {
      "type": "string",
      "nullable": true
     },
     "is_active": {
      "type": "boolean"
     },
     "created_at": {
      "type": "string",
      "format": "date-time",
      "example": "2026-10-14T09:15:00+02:00",
      "description": "Čas ISO 8601 s posunem (Europe/Prague).",
      "nullable": true
     },
     "uses": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/CouponUse"
      },
      "description": "Jen v detailu (nejvýš 200)."
     }
    }
   },
   "CouponInput": {
    "type": "object",
    "properties": {
     "code": {
      "type": "string",
      "minLength": 3,
      "maxLength": 40,
      "description": "Písmena, číslice, pomlčka a podtržítko; uloží se velkými písmeny. V rámci firmy jedinečný.",
      "example": "PODZIM50"
     },
     "name": {
      "type": "string",
      "maxLength": 80,
      "example": "Podzimní leták"
     },
     "type": {
      "type": "string",
      "enum": [
       "amount",
       "percent"
      ],
      "description": "amount = Kč, percent = %."
     },
     "value": {
      "type": "number",
      "example": 50
     },
     "min_total": {
      "type": "number",
      "format": "double",
      "example": 199.0,
      "description": "Minimální nákup; 0 nebo null = bez minima.",
      "nullable": true
     },
     "max_uses": {
      "type": "integer",
      "example": 100,
      "nullable": true
     },
     "valid_from": {
      "type": "string",
      "format": "date",
      "example": "2026-10-14",
      "description": "Den RRRR-MM-DD.",
      "nullable": true
     },
     "valid_to": {
      "type": "string",
      "format": "date",
      "example": "2026-10-14",
      "description": "Den RRRR-MM-DD.",
      "nullable": true
     },
     "note": {
      "type": "string",
      "maxLength": 255,
      "nullable": true
     },
     "is_active": {
      "type": "boolean",
      "example": true
     }
    },
    "description": "U POST jsou povinné code, type a value; u PATCH se mění jen zadaná pole.",
    "example": {
     "code": "PODZIM50",
     "name": "Podzimní leták",
     "type": "amount",
     "value": 50,
     "min_total": 300,
     "max_uses": 100,
     "valid_to": "2026-12-31"
    }
   },
   "Promotion": {
    "type": "object",
    "properties": {
     "id": {
      "type": "integer",
      "example": 5
     },
     "name": {
      "type": "string",
      "example": "Koláče 2+1"
     },
     "type": {
      "type": "string",
      "enum": [
       "price",
       "amount",
       "percent",
       "qty_percent",
       "nplus"
      ]
     },
     "value": {
      "type": "number",
      "example": 0
     },
     "min_qty": {
      "type": "number",
      "format": "double",
      "example": 2.0,
      "description": "qty_percent: od kolika kusů; nplus: kolik koupit.",
      "nullable": true
     },
     "free_qty": {
      "type": "integer",
      "description": "nplus: kolik zdarma.",
      "nullable": true
     },
     "qty_scope": {
      "type": "string",
      "enum": [
       "product",
       "promotion"
      ]
     },
     "starts_at": {
      "type": "string",
      "format": "date-time",
      "example": "2026-10-14T09:15:00+02:00",
      "description": "Čas ISO 8601 s posunem (Europe/Prague).",
      "nullable": true
     },
     "ends_at": {
      "type": "string",
      "format": "date-time",
      "example": "2026-10-14T09:15:00+02:00",
      "description": "Čas ISO 8601 s posunem (Europe/Prague).",
      "nullable": true
     },
     "note": {
      "type": "string",
      "nullable": true
     },
     "is_active": {
      "type": "boolean"
     },
     "product_ids": {
      "type": "array",
      "items": {
       "type": "integer"
      }
     },
     "category_ids": {
      "type": "array",
      "items": {
       "type": "integer"
      }
     },
     "created_at": {
      "type": "string",
      "format": "date-time",
      "example": "2026-10-14T09:15:00+02:00",
      "description": "Čas ISO 8601 s posunem (Europe/Prague).",
      "nullable": true
     }
    }
   },
   "PromotionInput": {
    "type": "object",
    "properties": {
     "name": {
      "type": "string",
      "maxLength": 80,
      "example": "Koláče 2+1"
     },
     "type": {
      "type": "string",
      "enum": [
       "price",
       "amount",
       "percent",
       "qty_percent",
       "nplus"
      ],
      "description": "price = akční cena v Kč, amount = sleva v Kč, percent = sleva v %, qty_percent = množstevní sleva v % od min_qty kusů, nplus = min_qty + free_qty zdarma."
     },
     "value": {
      "type": "number",
      "description": "Cena nebo sleva; u nplus se ignoruje.",
      "example": 0
     },
     "min_qty": {
      "type": "number",
      "format": "double",
      "example": 2.0,
      "description": "Množství (3 desetinná místa).",
      "nullable": true
     },
     "free_qty": {
      "type": "integer",
      "nullable": true
     },
     "qty_scope": {
      "type": "string",
      "enum": [
       "product",
       "promotion"
      ],
      "description": "product = za každý produkt zvlášť, promotion = dohromady za všechny produkty akce."
     },
     "starts_at": {
      "type": "string",
      "format": "date-time",
      "example": "2026-10-14T09:15:00+02:00",
      "description": "Začátek; bez posunu = čas v ČR.",
      "nullable": true
     },
     "ends_at": {
      "type": "string",
      "format": "date-time",
      "example": "2026-10-14T09:15:00+02:00",
      "description": "Konec.",
      "nullable": true
     },
     "product_ids": {
      "type": "array",
      "items": {
       "type": "integer"
      }
     },
     "category_ids": {
      "type": "array",
      "items": {
       "type": "integer"
      }
     },
     "note": {
      "type": "string",
      "maxLength": 255,
      "nullable": true
     },
     "is_active": {
      "type": "boolean",
      "example": true
     }
    },
    "description": "U POST jsou povinné name a type a alespoň jeden produkt nebo kategorie; u PATCH se mění jen zadaná pole, seznam produktů a kategorií se nahradí celý, je-li poslán.",
    "example": {
     "name": "Koláče 2+1",
     "type": "nplus",
     "min_qty": 2,
     "free_qty": 1,
     "product_ids": [
      87,
      88
     ],
     "starts_at": "2026-10-15T08:00",
     "ends_at": "2026-10-31T22:00"
    }
   }
  },
  "parameters": {
   "page": {
    "name": "page",
    "in": "query",
    "description": "Stránka od 1.",
    "schema": {
     "type": "integer",
     "minimum": 1,
     "default": 1
    }
   },
   "per_page": {
    "name": "per_page",
    "in": "query",
    "description": "Záznamů na stránku, nejvýš 200.",
    "schema": {
     "type": "integer",
     "minimum": 1,
     "maximum": 200,
     "default": 50
    }
   },
   "since_id": {
    "name": "since_id",
    "in": "query",
    "description": "Jen záznamy s id větším než zadané (průběžné stahování změn).",
    "schema": {
     "type": "integer",
     "example": 1420
    }
   },
   "order": {
    "name": "order",
    "in": "query",
    "description": "Řazení podle id.",
    "schema": {
     "type": "string",
     "enum": [
      "asc",
      "desc"
     ],
     "default": "asc"
    }
   },
   "from": {
    "name": "from",
    "in": "query",
    "description": "Od dne (včetně), RRRR-MM-DD.",
    "schema": {
     "type": "string",
     "format": "date",
     "example": "2026-10-01"
    }
   },
   "to": {
    "name": "to",
    "in": "query",
    "description": "Do dne (včetně), RRRR-MM-DD.",
    "schema": {
     "type": "string",
     "format": "date",
     "example": "2026-10-31"
    }
   },
   "active": {
    "name": "active",
    "in": "query",
    "description": "1 = jen aktivní, 0 = jen neaktivní, bez zadání vše.",
    "schema": {
     "type": "string",
     "enum": [
      "1",
      "0"
     ]
    }
   },
   "id": {
    "name": "id",
    "in": "path",
    "required": true,
    "schema": {
     "type": "integer"
    },
    "description": "Id záznamu."
   },
   "warehouse_id": {
    "name": "warehouse_id",
    "in": "query",
    "description": "Sklad; bez zadání výchozí sklad.",
    "schema": {
     "type": "integer",
     "example": 1
    }
   }
  },
  "responses": {
   "Unauthorized": {
    "description": "Neplatný, odvolaný nebo prošlý API klíč (`invalid_key`, `revoked_key`).",
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/Error"
      }
     }
    }
   },
   "Forbidden": {
    "description": "Vypnutý modul API nebo modul dané části (`module_disabled`), nebo klíč jen pro čtení u zápisu (`read_only_key`).",
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/Error"
      }
     }
    }
   },
   "NotFound": {
    "description": "Záznam neexistuje nebo patří jiné firmě (`not_found`).",
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/Error"
      }
     }
    }
   },
   "Validation": {
    "description": "Neplatná data (`validation`); v `errors` zpráva ke každému poli.",
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/Error"
      }
     }
    }
   },
   "RateLimited": {
    "description": "Překročený limit požadavků (`rate_limited`).",
    "headers": {
     "Retry-After": {
      "description": "Za kolik sekund to zkusit znovu.",
      "schema": {
       "type": "integer"
      }
     }
    },
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/Error"
      }
     }
    }
   }
  }
 }
}
