openapi: 3.0.3
info:
  title: LadyLike API
  description: |
    API інтернет-магазину жіночого одягу LadyLike (ladylike.ua).

    ## Базовий URL
    `https://ladylike.ua/uk` — українська версія.
    `https://ladylike.ua` — без локалі (повертає російськомовні дані).

    ## Вплив локалі на відповіді
    Локаль (`/uk` або без неї) впливає на такі поля:

    | Поле | З `/uk` | Без `/uk` |
    |------|---------|-----------| 
    | Назви товарів (`node_title`) | українська | російська |
    | Назви категорій (`tname`, `tdesc`) | українська | російська |
    | `url_alias` в товарах | `uk/Platia/...` | `Platia/...` |
    | `url_alias` в категоріях | `uk/Platia` | `Platia` |
    | `lang_pref` | `"uk/"` | `""` |
    | `cat_url` в хайлайтах | `/uk/Briuky/...` | `/Briuky/...` |
    | `parent_name` в категоріях | **завжди російська** | **завжди російська** |

    Поле `parent_name` в `/api/voc/1/list` **завжди російською** незалежно від локалі
    (особливість бекенду). Для навігації ієрархією використовуй `depth` та `url_alias`.

    ## Сесія
    Сесія створюється автоматично при першому запиті (анонімна).
    Авторизація не обов'язкова — замовлення можна оформити анонімно.
    Поле `flagged_class` в товарах залежить від сесії:
    - `"flag-action"` — товар не у вішлісті
    - `"unflag-action"` — товар вже у вішлісті

    ## Пагінація — важлива особливість
    Поле `pageCount` в відповіді API занижене на 1. Реальна кількість сторінок:
    ```
    totalPages = pageCount + 1
    ```
    Наступна сторінка існує якщо: `currentPage + 1 < pageCount + 1`

    ## Флоу для AI агента
    1. `GET /api/voc/1/list` — отримати дерево категорій
    2. `GET /api/view/NewModelFront/page` — отримати товари категорії з фільтрами
    3. `GET /api/app/view/node_json/default` — деталі обраного товару
    4. `GET /api/app/settings` — методи доставки та конфігурація
    5. `POST /amp/add_to_cart` — додати товар (потрібен `nid` і SKU розміру)
    6. `GET /amp/cart/data` — перевірити кошик
    7. `GET /api/cart/checkout` — методи доставки для поточного кошика
    8. Запитати у юзера: **телефон** (обов'язково), місто, відділення (опціонально)
    9. `POST /api/cart/order/place` — оформити замовлення

    ## Важливо для AI агента
    - **`order_last`** з `/api/cart/checkout` — не покладатись, завжди запитувати дані у юзера.
    - **Обов'язковий лише `phone`** при оформленні замовлення.
    - **`comments`** — завжди додавати: `"Замовлення оформлено через AI агента"`.
    - **`payment_method`** — завжди `"cod"` (накладений платіж).
    - **`uc_term_fields_data`** — може прийти як рядок `"null"`, не JSON null.
      Перевіряти: `value === "null" ? null : JSON.parse(value)`.

  version: 1.0.0
  contact:
    url: https://ladylike.ua

servers:
  - url: https://ladylike.ua/uk
    description: Основний сервер (українська локаль, рекомендований)
  - url: https://ladylike.ua
    description: Без локалі (повертає російськомовні дані)

tags:
  - name: Каталог
    description: Категорії, пошук, список товарів, фільтри
  - name: Товар
    description: Деталі товару, комплекти, варіанти, відгуки, наявність
  - name: Налаштування
    description: Глобальна конфігурація додатку
  - name: Кошик
    description: Управління кошиком
  - name: Замовлення
    description: Оформлення замовлення

paths:
  # ─── ПОШУК ──────────────────────────────────────────────────────────────────

  /api/search/autosuggest-image:
    get:
      tags: [Каталог]
      summary: Пошук товарів (автопідказка)
      description: |
        Пошук товарів за текстовим запитом. Повертає близько 20 товарів + 1 службовий
        елемент `autocomplete-more` в кінці масиву.

        **Поведінка при edge cases:**
        - Немає результатів → `{ items: [ { class: "autocomplete-more" } ] }` (тільки службовий елемент)
        - Порожній параметр `s=` → повертає `[]` (порожній масив, не об'єкт!)

        Останній елемент масиву завжди має `class: "autocomplete-more"` — це посилання
        "Шукати більше", не товар. Завжди ігноруй його при обробці.
      operationId: searchProducts
      parameters:
        - name: s
          in: query
          required: true
          description: |
            Пошуковий запит. При порожньому значенні повертає `[]` замість об'єкта.
          schema:
            type: string
          example: сукня
      responses:
        "200":
          description: |
            Список знайдених товарів. Увага: при порожньому `s` повертає масив `[]`,
            а не об'єкт `{ items: [] }`.
          content:
            application/json:
              schema:
                oneOf:
                  - type: object
                    properties:
                      items:
                        type: array
                        description: |
                          20 товарів + останній елемент з `class: "autocomplete-more"`.
                          Ігноруй елементи де присутнє поле `class`.
                        items:
                          $ref: "#/components/schemas/SearchResultItem"
                  - type: array
                    description: Порожній масив коли `s` не передано або порожній
                    maxItems: 0
                    items: {}
              examples:
                з_результатами:
                  summary: Знайдено товари
                  value:
                    items:
                      - nid: "1818"
                        value: "64200003"
                        title: Сукня в горох з рукавом довжиною в три чверті
                        image: https://ladylike.ua/f/imagecache/cart/zhenskaya-odezhda/2014/plate_v_goroh.jpg
                        url: https://ladylike.ua/uk/Platia/Suknia-v-gorokh-z-rukavom
                      - value: ""
                        title: Шукати більше
                        url: https://ladylike.ua/uk/catalog/all?search=%D1%81%D1%83%D0%BA%D0%BD%D1%8F
                        class: autocomplete-more
                без_результатів:
                  summary: Нічого не знайдено
                  value:
                    items:
                      - value: ""
                        title: Шукати більше
                        url: https://ladylike.ua/uk/catalog/all?search=xyzxyz
                        class: autocomplete-more

  # ─── КАТЕГОРІЇ ──────────────────────────────────────────────────────────────

  /api/voc/1/list:
    get:
      tags: [Каталог]
      summary: Список категорій товарів
      description: |
        Повертає плоский список усіх категорій з ієрархією через поле `depth`.

        **Побудова дерева:**
        - `depth: 0` — коренева категорія (Сукні, Блузи, Брюки...)
        - `depth: 1` — підкатегорія (Сарафани, Футболки...)
        - `depth: 2` — під-підкатегорія (Сорочки, Майки...)

        **Важливо:** `parent_name` завжди російською незалежно від локалі.
        Для навігації ієрархією надійніше використовувати `depth` та `url_alias`.

        `tid` з цього списку використовується як параметр `args` в ендпоінтах каталогу.

        Повний URL категорії: `https://ladylike.ua/` + `url_alias`
      operationId: getCategories
      responses:
        "200":
          description: Плоский список категорій
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: "#/components/schemas/Category"
              example:
                items:
                  - tid: "5"
                    tname: Сукні
                    tdesc: <h1>Купити модні сукні</h1>
                    tphoto: https://ladylike.ua/f/imagecache/uc_category/womens-clothing/2026/plate.jpg
                    parent_name: null
                    url_alias: uk/Platia
                    depth: 0
                  - tid: "6"
                    tname: Сарафани
                    tdesc: <h1>Купити сарафани</h1>
                    tphoto: https://ladylike.ua/f/imagecache/uc_category/womens-clothing/2026/sarafan.jpg
                    parent_name: Платья
                    url_alias: uk/Sarafany
                    depth: 1

  # ─── КАТАЛОГ ТОВАРІВ ────────────────────────────────────────────────────────

  /api/view/clothes/page_4:
    get:
      tags: [Каталог]
      summary: Каталог товарів з фільтрами та пагінацією
      description: |
        Основний ендпоінт каталогу. Повертає 40 товарів на сторінку.

        **Фільтрація по категорії:** передай `args` = `tid` з `/api/voc/1/list`.
        Без `args` — всі товари магазину (2500+).

        **Синтаксис фільтрів** (отримати ID з `/api/view-filters/clothes/page_4`):
        ```
        field_color[90]=true&field_color[10]=true   ← кілька кольорів
        pattr_size[2]=true&pattr_size[4]=true        ← кілька розмірів
        store_id=7                                    ← магазин (без дужок!)
        ```

        **Пагінація:** `totalPages = pageCount + 1` (API занижує на 1).

        **Знижки:** товари зі знижкою містять додаткові поля `old_price`,
        `discount_percent` — вони можуть з'являтись у будь-якому списку каталогу.
      operationId: getCatalogItems
      parameters:
        - name: args
          in: query
          required: false
          description: ID категорії (`tid`) з `/api/voc/1/list`
          schema:
            type: string
          example: "5"
        - name: page
          in: query
          required: false
          description: Номер сторінки (з 0)
          schema:
            type: integer
            default: 0
        - name: sort_by
          in: query
          required: false
          schema:
            type: string
            enum: [created, price, sale]
            default: created
        - name: sort_order
          in: query
          required: false
          schema:
            type: string
            enum: [ASC, DESC]
            default: DESC
        - name: limit
          in: query
          required: false
          description: Кількість товарів на сторінці
          schema:
            type: integer
            default: 40
        - name: img_format
          in: query
          required: false
          description: Формат зображень (наприклад `400_400`)
          schema:
            type: string
          example: 400_400
        - name: store_id
          in: query
          required: false
          description: |
            Фільтр по магазину. ID магазину з `/api/view-filters/clothes/page_4`.
            Передається без дужок: `store_id=7`
          schema:
            type: string
          example: "7"
        - name: field_color[{id}]
          in: query
          required: false
          description: |
            Фільтр по кольору. `{id}` — числовий ID кольору з фільтрів.
            Приклад: `field_color[90]=true` (чорний).
            Можна передати кілька.
          schema:
            type: string
            enum: ["true"]
        - name: pattr_size[{id}]
          in: query
          required: false
          description: |
            Фільтр по розміру. `{id}` — числовий ID розміру з фільтрів.
            Приклад: `pattr_size[2]=true` (36 EU / S).
          schema:
            type: string
            enum: ["true"]
        - name: field_fabric[{id}]
          in: query
          required: false
          description: Фільтр по тканині. ID з `/api/view-filters/clothes/page_4`.
          schema:
            type: string
            enum: ["true"]
        - name: field_fabric_pattern[{id}]
          in: query
          required: false
          description: Фільтр по візерунку тканини.
          schema:
            type: string
            enum: ["true"]
        - name: field_fabric_warm[{id}]
          in: query
          required: false
          description: Фільтр по утепленій тканині.
          schema:
            type: string
            enum: ["true"]
        - name: field_features[{id}]
          in: query
          required: false
          description: Фільтр по особливостях крою.
          schema:
            type: string
            enum: ["true"]
        - name: field_fit[{id}]
          in: query
          required: false
          description: Фільтр по посадці (висока/середня/низька).
          schema:
            type: string
            enum: ["true"]
      responses:
        "200":
          description: Список товарів з пагінацією
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CatalogPage"

  /api/view/clothes/page_3:
    get:
      tags: [Каталог]
      summary: Нові надходження
      description: |
        Нові товари, відсортовані за датою додавання (новіші першими).
        Структура ідентична `/api/view/clothes/page_4`.
        Підтримує `limit` та `page` параметри.
      operationId: getNewArrivals
      parameters:
        - name: page
          in: query
          required: false
          schema:
            type: integer
            default: 0
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            default: 12
      responses:
        "200":
          description: Нові надходження
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CatalogPage"

  /api/view/clothes/product_most_popular:
    get:
      tags: [Каталог]
      summary: Найпопулярніші товари (всі категорії)
      description: |
        Товари відсортовані за кількістю продажів (`total_sold`).
        Підтримує `limit`, `args` (категорія) та `img_format`.
        `currentPage` завжди `null`. Без пагінації.

        Відрізняється від `product_popular`:
        - охоплює всі 2500+ товарів
        - немає поля `flag_content_content_id`
      operationId: getMostPopular
      parameters:
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            default: 20
        - name: args
          in: query
          required: false
          description: ID категорії для фільтрації
          schema:
            type: string
        - name: img_format
          in: query
          required: false
          schema:
            type: string
          example: 400_400
      responses:
        "200":
          description: Популярні товари
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CatalogPage"

  /api/view/clothes/product_popular:
    get:
      tags: [Каталог]
      summary: Популярні товари (скорочений список)
      description: |
        Відфільтрований список популярних товарів (~154 товари, не всі 2500+).
        Підтримує `limit`. `currentPage` завжди `null`.

        Відрізняється від `product_most_popular`:
        - менший пул товарів (`productCount ~154`)
        - містить поле `flag_content_content_id` (дублює `nid`, службове)
        - `flagged_class` може бути `"unflag-action"` якщо товар вже у вішлісті
      operationId: getPopularItems
      parameters:
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            default: 5
      responses:
        "200":
          description: Популярні товари
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CatalogPage"

  /api/view/clothes/sale_new:
    get:
      tags: [Каталог]
      summary: Товари зі знижками
      description: |
        Товари з активними знижками, відсортовані за датою початку акції.

        **Параметр `args=11`** — ID категорії знижок (фіксований, передається додатком).

        Кожен товар містить поля знижки:
        `old_price`, `price` (знижкова), `discount_percent`.

        Знижкові поля також можуть з'являтись у звичайному каталозі (`page_4`) —
        якщо на товар діє акція.

        `currentPage` завжди `null`.
      operationId: getSaleItems
      parameters:
        - name: args
          in: query
          required: false
          description: ID категорії знижок. Додаток передає `11`.
          schema:
            type: string
          example: "11"
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            default: 10
      responses:
        "200":
          description: Товари зі знижками
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CatalogPage"

  # ─── ФІЛЬТРИ ────────────────────────────────────────────────────────────────

  /api/view-filters/clothes/page_4:
    get:
      tags: [Каталог]
      summary: Доступні фільтри каталогу
      description: |
        Повертає масив груп фільтрів з усіма можливими значеннями та їх ID.

        **Групи фільтрів:**
        - `pattr_1` → `pattr_size` — розміри (EU + укр. розмір)
        - `field_color_value_many_to_one` → `field_color` — кольори (з HEX)
        - `field_fabric_value_many_to_one` → `field_fabric` — тип тканини
        - `field_fabric_warm_value_many_to_one` → `field_fabric_warm` — утеплена тканина
        - `field_fabric_pattern_value_many_to_one` → `field_fabric_pattern` — візерунок
        - `field_features_value_many_to_one` → `field_features` — особливості крою
        - `field_fit_value_many_to_one` → `field_fit` — посадка (висока/середня/низька)
        - `store_id` — фізичні магазини (з адресами)

        Групи з порожнім `label` та `options` (`field_makeup_value`, `model`, `title`,
        `field_title_ua_value`) — службові, ігноруй їх.

        **Використання ID у фільтрах каталогу:**
        `field_color[90]=true` — де `90` це `id` з `options`.
        Виняток: `store_id=7` (без дужок).
      operationId: getCatalogFilters
      responses:
        "200":
          description: Масив груп фільтрів
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/FilterGroup"
              example:
                - id: pattr_1
                  label: Розмір
                  options:
                    - id: "1"
                      name: 34 EU (40 укр.) XS
                    - id: "2"
                      name: 36 EU (42 укр.) S
                    - id: "4"
                      name: 40 EU (46 укр.) M
                    - id: "6"
                      name: 44 EU (50 укр.) L
                    - id: "9"
                      name: 46 EU (52 укр.) L/XL
                    - id: "10"
                      name: 48 EU (54 укр.) XL
                - id: field_color_value_many_to_one
                  label: Колір
                  options:
                    - id: "90"
                      name: чорний
                      hex: "#000000"
                    - id: "-1"
                      name: білий
                      hex: "#FFFFFF"
                    - id: "10"
                      name: червоний
                      hex: "#FF0000"
                - id: store_id
                  label: Магазин
                  options:
                    - id: "7"
                      name: ТЦ Дарниця
                    - id: "30"
                      name: ТЦ Глобус (Майдан Незалежності)

  # ─── ХАЙЛАЙТИ ───────────────────────────────────────────────────────────────

  /api/category/hightlights/{tid}:
    get:
      tags: [Каталог]
      summary: Хайлайти категорії (готові фільтри-посилання)
      description: |
        Повертає об'єкт з двома типами записів змішаних під одним ключем:

        **Тип 1 — категорії** (ключі: числові tid, наприклад `"1"`, `"2"`):
        Містять `tid`, `name`, `img_url`, `cat_url`. Без поля `filter`.

        **Тип 2 — хайлайти** (ключі: `high_N`, наприклад `"high_1"`, `"high_9"`):
        Готові фільтри-посилання з полем `filter` та трьома розмірами зображень.
        Деякі хайлайти мають `filter: null` — це посилання на підрозділ без фільтру
        (наприклад "Вечірні сукні", "На весілля до подруги").

        Спеціальне значення `tid = "topsearch"` повертає хайлайти для сторінки пошуку
        (суміш категорій верхнього рівня + хайлайти різних категорій).

        Поле `filter` хайлайту містить один query param для `/api/view/clothes/page_4`:
        `field_fit`, `field_features`, `field_fabric`, `field_fabric_pattern`, `pattr_size`.
      operationId: getCategoryHighlights
      parameters:
        - name: tid
          in: path
          required: true
          description: |
            ID категорії з `/api/voc/1/list`, або рядок `topsearch`
            для хайлайтів сторінки пошуку.
          schema:
            type: string
          example: "3"
      responses:
        "200":
          description: |
            Об'єкт з динамічними ключами. Числові ключі — категорії,
            ключі `high_N` — хайлайти.
          content:
            application/json:
              schema:
                type: object
                additionalProperties:
                  oneOf:
                    - $ref: "#/components/schemas/CategoryHighlight"
                    - $ref: "#/components/schemas/CategoryShortcut"
              example:
                "5":
                  tid: "5"
                  name: Сукні
                  img_url: https://ladylike.ua/f/imagecache/uc_category/womens-clothing/2026/plate.jpg
                  cat_url: /uk/Platia
                high_1:
                  name: Сукні з льону
                  filter:
                    field_fabric: "5"
                  tid: 5
                  img_url: https://ladylike.ua/f/imagecache/uc_category/womens-clothing/2025/plate_zheltoe.jpg
                  img_small_url: https://ladylike.ua/f/imagecache/cart/womens-clothing/2025/plate_zheltoe.jpg
                  img_66_99_url: https://ladylike.ua/f/imagecache/66_99/womens-clothing/2025/plate_zheltoe.jpg
                  path: Platia/field_fabric=5/filter
                  cat_url: /uk/Platia/field_fabric=5/filter
                high_34:
                  name: Вечірні сукні
                  filter: null
                  tid: 104
                  img_url: https://ladylike.ua/f/imagecache/uc_category/womens-clothing/2025/plate_chernoe.jpg
                  img_small_url: https://ladylike.ua/f/imagecache/cart/womens-clothing/2025/plate_chernoe.jpg
                  img_66_99_url: https://ladylike.ua/f/imagecache/66_99/womens-clothing/2025/plate_chernoe.jpg
                  path: Platia/vechirni
                  cat_url: /uk/Platia/vechirni

  # ─── БАНЕР ──────────────────────────────────────────────────────────────────

  /api/banner/newsmsg/slim:
    get:
      tags: [Каталог]
      summary: Промо-банер
      description: |
        Повертає поточний промо-банер магазину з URL зображення та терміном дії.
        `start` і `end` — Unix timestamps.
      operationId: getBanner
      responses:
        "200":
          description: Банер
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Banner"
              example:
                image: https://ladylike.ua/uk/f/valentines_day_2026_slim.jpg
                start: "1770760800"
                end: "1771192800"

  # ─── ВІДГУКИ ────────────────────────────────────────────────────────────────

  /amp/review/toplist:
    get:
      tags: [Каталог]
      summary: Топ відгуків покупців
      description: |
        Повертає список останніх/найкращих відгуків покупців з посиланням на товар.
      operationId: getTopReviews
      responses:
        "200":
          description: Список відгуків
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: "#/components/schemas/Review"

  # ─── ТОВАР ─────────────────────────────────────────────────────────────────

  /api/app/view/node_json/default:
    get:
      tags: [Товар]
      summary: Деталі товару
      description: |
        Повна інформація про товар. Повертає масив з одним об'єктом `[{...}]`.
        При невалідному `nid` повертає порожній масив `[]`.

        **Ціна та знижка:**
        - `active_real_price` — поточна ціна (вже зі знижкою якщо є акція)
        - `discount_amount` — сума знижки в гривнях (рядок, порожній якщо немає)
        - Стара ціна = `parseFloat(active_real_price) + parseFloat(discount_amount)`
        - `discount_percent` — відсоток знижки (рядок, порожній якщо немає)
        - `uc_products_sell_price` — оригінальна ціна без знижки (завжди актуальна)
        - При знижці: `activation` і `expiration` — Unix timestamps початку/кінця акції

        **Розміри з наявністю** — парсити з `stock_group_concat`:
        `"36 (13), 38 (0), 40 (10)"` → 36 є (13 шт), 38 немає, 40 є (10 шт).
        Розмір `"01"` — службовий, ігнорувати.

        **Поля з `|` роздільником** (`field_color_value`, `field_features_value` тощо)
        містять кілька значень — брати перший елемент до `|` для відображення,
        розбити за `|` і відфільтрувати порожні для повного списку.

        **`field_wash_values`** — `null` якщо інструкції не вказані, або об'єкт з
        `values` (текстові описи) та `images` (відносні шляхи піктограм).

        **`uc_term_fields_data`** — JSON-рядок або рядок `"null"` (не JSON null).
        Перевіряти: `value === "null" ? null : JSON.parse(value)`.
        Ключі: `tid` категорії → `vid` → `oid` (ID розміру з фільтрів) → міри.
        Набір мір залежить від типу одягу: сукні — обхват грудей, брюки — довжина,
        стегна, талія, кроковий шов тощо.

        **Локаль** (`/uk` vs без):
        - З `/uk`: є `field_title_ua_value`, `field_description_ua_value`; немає `node_title`, `node_revisions_body`
        - Без `/uk`: є `node_title` (рос), `node_revisions_body` (рос); немає `field_title_ua_value`
        - `taxonomy_terms[].url` та `breadcrumbs[].url` — з або без `/uk/` префіксу

        **Службові поля** у відповіді (ігнорувати): `node_vid`, `active_price`, `type`,
        `ops`, `votingapi_cache_*`, `node_data_field_*`, `uc_sales_planning_type`.
      operationId: getProductDetails
      parameters:
        - name: args
          in: query
          required: true
          description: ID товару (`nid`)
          schema:
            type: string
          example: "9879"
      responses:
        "200":
          description: |
            Масив з одним товаром, або порожній масив `[]` якщо `nid` не знайдено.
          content:
            application/json:
              schema:
                oneOf:
                  - type: array
                    minItems: 1
                    maxItems: 1
                    items:
                      $ref: "#/components/schemas/ProductDetail"
                  - type: array
                    maxItems: 0
                    description: Порожній масив — товар не знайдено
                    items: {}

  /api/app/view/node_json/product_kit:
    get:
      tags: [Товар]
      summary: Деталі комплекту товарів (kit)
      description: |
        Повертає масив з кількох товарів що входять до комплекту.
        Структура кожного елементу аналогічна `/api/app/view/node_json/default`,
        але з додатковими полями комплекту.

        **Ціна комплекту** — обчислюється клієнтом як сума `active_real_price`
        всіх елементів масиву.

        **Специфічні поля kit:**
        - `type_2: "Набор товаров"` — маркер комплекту (відсутнє в звичайному товарі)
        - `title_1` — назва окремого предмету в комплекті
        - `field_title_ua_value_1` — українська назва предмету
        - `field_kit_video_fid` — відео комплекту (замість `field_video_fid`)
        - `node_uc_product_kits_nid` — ID вузла комплекту
        - `node_uc_product_kits_vid` — дублює `node_uc_product_kits_nid`. Службове.
        - `node_uc_product_kits_type: "product_kit"` — тип вузла
        - `sell_price` — оригінальна ціна предмету (рядок)

        **Наявність в магазинах для kit:**
        передавай `model_1` всіх елементів через `_`: `amp/stock/info/model1_model2`
      operationId: getProductKit
      parameters:
        - name: args
          in: query
          required: true
          description: ID товару-комплекту (`nid`)
          schema:
            type: string
          example: "11080"
      responses:
        "200":
          description: Масив товарів що входять до комплекту
          content:
            application/json:
              schema:
                type: array
                minItems: 2
                items:
                  $ref: "#/components/schemas/ProductDetail"

  /api/view/NewModelFront/color_block:
    get:
      tags: [Товар]
      summary: Варіанти товару за кольором
      description: |
        Повертає список товарів того ж фасону в інших кольорах.

        Структура відповіді: `{ items: [{ values: [...] }] }` з пагінаційними полями.
        `productCount: null`, `pageCount: 0` — пагінація не підтримується.
        `h1` містить назву товару (може бути російською незалежно від локалі).

        Кожен елемент `values[]` — спрощена картка товару з мініатюрою (`uc_thumbnail`).
        Службові поля з довгими назвами `node_node_data_field_node_reference_color_*`
        — ігнорувати, використовувати лише `nid`, `field_image_cache_fid`, `price`,
        `url_alias`, `flagged_class`, `flagged_token`.
      operationId: getColorVariants
      parameters:
        - name: args
          in: query
          required: true
          description: ID товару (`nid`)
          schema:
            type: string
          example: "11234"
        - name: list_carousel
          in: query
          required: false
          description: Режим каруселі. Завжди передавати `1`.
          schema:
            type: integer
            enum: [1]
            default: 1
      responses:
        "200":
          description: Варіанти за кольором
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ValuesListResponse"

  /api/view/NewModelFront/relative_clothes:
    get:
      tags: [Товар]
      summary: Схожі товари
      description: |
        Повертає список схожих товарів з тієї ж категорії.

        Структура аналогічна `color_block`: `{ items: [{ values: [...] }] }`.
        Кожен елемент `values[]` — спрощена картка з фото у форматі `img_format`.
        Службові поля `node_node_data_field_node_reference_*` — ігнорувати.
        Товари зі знижкою містять `old_price`, `discount_percent`.
      operationId: getRelatedClothes
      parameters:
        - name: args
          in: query
          required: true
          description: ID товару (`nid`)
          schema:
            type: string
          example: "9879"
        - name: img_format
          in: query
          required: false
          description: Розмір зображення
          schema:
            type: string
            default: product_list_widget
          example: product_list_widget
        - name: list_carousel
          in: query
          required: false
          schema:
            type: integer
            enum: [1]
            default: 1
      responses:
        "200":
          description: Схожі товари
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ValuesListResponse"

  /amp/order/related/products/{nid}:
    get:
      tags: [Товар]
      summary: Часто купують разом
      description: |
        Товари які часто купують разом з даним товаром.

        Структура: `{ items: [{ values: [...] }] }`.
        Елементи `values[]` мінімальні: `nid`, `img_src`, `url_alias`, `price`, `price_sign`.
        Зображення у форматі `uc_thumbnail`.
        `price` — integer (на відміну від більшості інших ендпоінтів де string).
      operationId: getFrequentlyBoughtTogether
      parameters:
        - name: nid
          in: path
          required: true
          description: ID товару
          schema:
            type: string
          example: "9879"
      responses:
        "200":
          description: Товари що часто купують разом
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      properties:
                        values:
                          type: array
                          items:
                            $ref: "#/components/schemas/RelatedProductItem"

  /amp/stock/info/{model}:
    get:
      tags: [Товар]
      summary: Наявність товару в магазинах
      description: |
        Наявність конкретного товару по кожному фізичному магазину з розбивкою
        по розмірах.

        `model` = поле `model_1` з деталей товару.
        Для комплекту: `model1_model2` (через підкреслення).

        **`size-class`:**
        - `"active"` — розмір є в наявності в цьому магазині
        - `"inactive"` — немає, але можна замовити (доставка `delivery` днів)

        **`delivery`:**
        - `"0"` — є в наявності
        - `"1-2"` — доставка 1-2 дні між магазинами

        **`size-option`** — внутрішній ID варіанту розміру
        (відповідає `uc_product_stock_clothes_sizes` в деталях товару).
      operationId: getStoreAvailability
      parameters:
        - name: model
          in: path
          required: true
          description: Артикул товару (`model_1`). Для комплекту через `_`.
          schema:
            type: string
          example: "35570001"
      responses:
        "200":
          description: Список магазинів з наявністю по розмірах
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      properties:
                        values:
                          type: array
                          items:
                            $ref: "#/components/schemas/StoreAvailability"

  /amp/review/{nid}/list:
    get:
      tags: [Товар]
      summary: Відгуки про товар
      description: |
        Повертає масив відгуків покупців про товар.
        Якщо відгуків немає — порожній масив `[]`.

        `fivestar_rating` — оцінка 0–100 (100 = 5 зірок).
        `sizematch` — відповідність розміру, може бути `null`.
        `timestamp` — Unix timestamp дати відгуку.
      operationId: getProductReviews
      parameters:
        - name: nid
          in: path
          required: true
          description: ID товару
          schema:
            type: string
          example: "9879"
      responses:
        "200":
          description: Масив відгуків (порожній якщо немає)
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/ProductReview"

  /amp/review/add:
    post:
      tags: [Товар]
      summary: Додати відгук про товар
      description: |
        Публікує відгук покупця. Приймає `multipart/form-data`.
        При успіху повертає `{ "message": "Дякуємо за відгук!. " }`.
        При помилці валідації — `{ "verifyErrors": { "message": "..." } }`.
        При системній помилці — `{ "error": "..." }`.
      operationId: submitReview
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required: [nid, fivestar, review, sizem]
              properties:
                nid:
                  type: string
                  example: "9879"
                fivestar:
                  type: string
                  description: Оцінка 0–100 (100 = 5 зірок)
                  example: "100"
                review:
                  type: string
                  example: Чудова якість, відповідає розміру
                sizem:
                  type: string
                  description: Розмір який обрав покупець
                  example: "36"
      responses:
        "200":
          description: Результат публікації відгуку
          content:
            application/json:
              schema:
                oneOf:
                  - type: object
                    description: Успішно
                    properties:
                      message:
                        type: string
                        example: "Дякуємо за відгук!. "
                  - type: object
                    description: Помилка валідації
                    properties:
                      verifyErrors:
                        type: object
                        properties:
                          message:
                            type: string
                  - type: object
                    description: Системна помилка
                    properties:
                      error:
                        type: string

  /api/app/view/node_json/feedback:
    get:
      tags: [Товар]
      summary: Мета-дані форми відгуку
      description: |
        Мінімальні дані товару для форми відгуку.
        Відповідь — масив, брати лише перший елемент `data[0]`.

        **Важливо:** сервер повертає масив з дублікатами одного і того ж товару
        (кількість елементів залежить від кількості розмірів). Використовувати
        тільки `data[0]`.

        Містить: `title`, `field_image_cache_fid`, `nid`, `taxonomy_terms`, `breadcrumbs`.
        Відсутні поля ціни, розмірів, складу.

        **Формат зображень:** `url` використовує формат `cart` (менший розмір для
        кошика), `url_big` — `product_full` (повний розмір).
      operationId: getFeedbackProduct
      parameters:
        - name: args
          in: query
          required: true
          description: ID товару (`nid`)
          schema:
            type: string
          example: "9879"
      responses:
        "200":
          description: |
            Масив з дублікатами — брати тільки перший елемент `data[0]`.
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    nid:
                      type: string
                    type_1:
                      type: string
                      description: Тип вузла. Завжди `"clothes"`.
                      example: clothes
                    title:
                      type: string
                    field_title_ua_value:
                      type: string
                    node_type:
                      type: string
                      example: clothes
                    node_vid:
                      type: string
                      description: Службове. Дублює `nid`.
                    field_wash_values:
                      nullable: true
                      description: Завжди `null` у feedback відповіді.
                    field_image_cache_fid:
                      type: array
                      description: |
                        Галерея зображень. `url` — формат `cart`,
                        `url_big` — формат `product_full`.
                      items:
                        type: object
                        properties:
                          url:
                            type: string
                            format: uri
                            description: Зображення у форматі `cart`
                          url_big:
                            type: string
                            format: uri
                            description: Повний розмір `product_full`
                    taxonomy_terms:
                      type: array
                      items:
                        $ref: "#/components/schemas/TaxonomyTerm"
                    breadcrumbs:
                      type: array
                      items:
                        type: array
                        items:
                          $ref: "#/components/schemas/BreadcrumbItem"

  /amp/product/promomsg/{nid}:
    get:
      tags: [Товар]
      summary: Промо-повідомлення товару
      description: |
        Динамічне повідомлення для сторінки товару —
        наприклад кількість відвідувачів що переглядають зараз.

        Структура: `{ items: [{ values: [{ msg: "..." }] }] }`.
      operationId: getProductPromoMessage
      parameters:
        - name: nid
          in: path
          required: true
          description: ID товару
          schema:
            type: string
          example: "9879"
      responses:
        "200":
          description: Промо-повідомлення
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      properties:
                        values:
                          type: array
                          items:
                            type: object
                            properties:
                              msg:
                                type: string
                                example: 37 відвідув. переглядають цю модель

  /amp/flag/flag/recently_viewed/{nid}:
    post:
      tags: [Товар]
      summary: Позначити товар як нещодавно переглянутий
      description: |
        Додає товар до списку нещодавно переглянутих для поточної сесії.
        При успіху повертає `{ "message": "flag" }`.
        Не потребує тіла запиту.
      operationId: markAsRecentlyViewed
      parameters:
        - name: nid
          in: path
          required: true
          description: ID товару
          schema:
            type: string
          example: "9879"
      responses:
        "200":
          description: Успішно позначено
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: flag

  # ─── НАЛАШТУВАННЯ / КОШИК / ЗАМОВЛЕННЯ ────────────────────────────────────

  # ─── НАЛАШТУВАННЯ ───────────────────────────────────────────────────────────

  /api/app/settings:
    get:
      tags: [Налаштування]
      summary: Глобальні налаштування додатку
      description: |
        Повертає конфігурацію магазину: умови доставки, список магазинів з
        координатами, статуси замовлень, LiqPay merchant ID.

        **Корисно для AI агента:**
        - `shipping[0].free_shipping_min_total` — мінімальна сума для безкоштовної доставки (зараз 2000 грн), може динамічно змінюватись
        - `shipping[1].standard_price` — ціна стандартної доставки
        - `return.max_days` — кількість днів для повернення (зараз 30)
        - `order_statuses` — всі можливі статуси замовлень з перекладами
        - `stores` — всі магазини (активні та неактивні, `disabled: "1"` = закрито)

        Магазини з `disabled: "0"` та `latitude != "0.000000"` мають реальні координати.

        **`shipping`** — масив з двох елементів:
        - `[0]` містить `free_shipping_min_total` і `price: 0`
        - `[1]` містить `standard_price`
      operationId: getAppSettings
      responses:
        "200":
          description: Глобальні налаштування
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AppSettings"

  # ─── КОШИК ──────────────────────────────────────────────────────────────────

  /amp/add_to_cart:
    post:
      tags: [Кошик]
      summary: Додати товар до кошика
      description: |
        Додає один або кілька товарів до кошика поточної сесії.

        **Формування SKU:**
        `SKU = model_1 + sizeNumber`
        де `model_1` — артикул з деталей товару (`/api/app/view/node_json/default`),
        `sizeNumber` — числова частина розміру (наприклад `"36 EU"` → `"36"`).

        Приклад: `model_1 = "35570001"`, розмір `"36 EU"` → SKU = `"3557000136"`.

        **Формат тіла** (`application/x-www-form-urlencoded`):
        ```
        skus[{nid}]={model_1}{sizeNumber}
        ```
        Для кількох товарів — кілька параметрів:
        ```
        skus[9879]=3557000136&skus[8983]=2118100890
        ```

        При успіху повертає `cart_item_id` — потрібен для оновлення/видалення позиції.
        `message` містить інформацію про термін доставки.

        **Помилка** — якщо розміру немає або SKU невалідний, повертає
        `{ "verifyErrors": { "name": "size", "message": "..." } }`.
        HTTP статус при помилці — **200** (не 4xx).
      operationId: addToCart
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              description: |
                Ключі у форматі `skus[{nid}]`, значення — SKU розміру.
                Можна передати кілька товарів одночасно.
              additionalProperties:
                type: string
            example:
              "skus[9879]": "3557000136"
      responses:
        "200":
          description: Результат додавання
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: "#/components/schemas/AddToCartSuccess"
                  - $ref: "#/components/schemas/CartError"
              examples:
                успішно:
                  value:
                    cart_id: 24d4b9c802405d50fbe1e0fdd97d381d
                    cart_item_id: "221308"
                    size: 36 EU
                    message: Відправка сьогодні. Доставка у ваше відділення пошти - Субота, 23 Травень.
                помилка:
                  value:
                    verifyErrors:
                      name: size
                      message: "😔 На жаль, розмір розпродано."

  /amp/cart/data:
    get:
      tags: [Кошик]
      summary: Вміст кошика
      description: |
        Повертає всі товари в кошику поточної сесії з цінами та атрибутами.

        **Порожній кошик:** `items: [{ values: [] }]`, `productCount: null`, `total: null`.

        **Ціни** у форматі рядка з комою: `"410,00 грн"` — не число.

        **`cid`** — ID позиції в кошику, потрібен для:
        - `POST /amp/cart/update` — змінити кількість або видалити

        **`deliveryText`** — може містити HTML розмітку з промо-повідомленням.
        Наприклад: `"<div style=\"color: #ffc107;\">У подарунок до замовлення знижкова карта до <strong>-10%</strong></div>"`.
        Показувати юзеру після декодування HTML або як plain text.

        **`sku`** — внутрішній ID варіанту розміру.
        **`attrs`** — розмір у читабельному форматі: `"36 EU (42 укр.) S"`.
        **`colors`** — колір українською.
        **`price_old`** — стара ціна якщо є знижка, порожній рядок якщо немає.
        **`price_qty`** — загальна ціна позиції (ціна × qty).
      operationId: getCartData
      responses:
        "200":
          description: Вміст кошика
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CartData"
              examples:
                з_товарами:
                  value:
                    items:
                      - values:
                          - cart_id: 24d4b9c802405d50fbe1e0fdd97d381d
                            cid: "221308"
                            nid: "9879"
                            qty: "1"
                            title: Майка жіноча біла
                            price: "410,00 грн"
                            price_old: ""
                            image: https://ladylike.ua/f/imagecache/uc_thumbnail/womens-clothing/2026/mayka_zhenskaya_belaya.jpg
                            url: /uk/Bluzy/Bluzy-s-korotkym-rukavom/Majky/Majka-zhenskaia-belaia
                            price_qty: "410,00 грн"
                            attrs: 36 EU (42 укр.) S
                            colors: Білий
                            size: "36"
                            sku: "3557000136"
                    productCount: 1
                    total: "410,00 грн"
                    deliveryText: ""
                порожній:
                  value:
                    items:
                      - values: []
                    productCount: null
                    total: null
                    deliveryText: ""

  /amp/cart/update:
    post:
      tags: [Кошик]
      summary: Оновити або видалити позицію кошика
      description: |
        Змінює кількість товару або видаляє позицію з кошика.

        `qty: 0` — видалити позицію.
        `qty: N` — встановити кількість N (додає N одиниць до поточної кількості).

        `ci_id` = `cid` з відповіді `/amp/cart/data`.

        **Важливо:** відповідь **завжди** `{ "success": true, "message": "Item removed successfully." }`
        незалежно від того видалення це (qty=0) чи зміна кількості (qty=N).
        Для перевірки нової кількості — зробити окремий `GET /amp/cart/data`.

        При невалідному `ci_id` повертає рядок `"Item is not set"` або
        `"Item not found"` — **не JSON**, треба обробляти окремо.
      operationId: updateCartItem
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              required: [ci_id, qty]
              properties:
                ci_id:
                  type: string
                  description: ID позиції кошика (`cid` з `/amp/cart/data`)
                  example: "221308"
                qty:
                  type: integer
                  description: |
                    Нова кількість. `0` = видалити позицію.
                    При `qty > 0` — додає до поточної кількості.
                  example: 0
      responses:
        "200":
          description: Результат оновлення (однаковий для видалення і зміни кількості)
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  message:
                    type: string
                    example: Item removed successfully.

  # ─── ЗАМОВЛЕННЯ ─────────────────────────────────────────────────────────────

  /api/cart/checkout:
    get:
      tags: [Замовлення]
      summary: Дані для оформлення замовлення
      description: |
        Повертає дані необхідні для оформлення замовлення: дані останнього
        замовлення сесії та доступні методи доставки з цінами.

        **`order_last`** — дані останнього замовлення прив'язаного до поточного
        session cookie. Присутній якщо в цій сесії вже було замовлення.

        **⚠️ Для AI агента: не покладатись на `order_last`.**
        Ці дані можуть належати іншому або старому замовленню. Завжди запитувати
        дані у юзера в чаті — мінімум `phone`. Інші поля опціональні.

        **`shipping_methods.options`** — об'єкт `{ key: label }` де:
        - ключ: `"flatrate_10---0"` — передається в `placeOrder` як `shipping_method`
        - значення: `"Нова Пошта: 90,00 грн"` — для відображення
        - `&#039;` в значеннях — HTML-ентіті апострофа, декодувати перед відображенням

        **`shipping_methods.rates`** — об'єкт `{ key: cost }` де cost = число (грн).

        **`shipping_methods.options_ext`** — службове поле для розширених опцій
        деяких методів доставки (наприклад вибір магазину для резервування).

        **`base_fields`** і **`extra_fields`** — службові поля форми замовлення,
        для AI агента не потрібні.

        **Підтверджені методи доставки:**
        - `flatrate_10---0` — Нова Пошта: 90 грн
        - `flatrate_11---0` — Укрпошта: 55 грн
        - `flatrate_12---0` — Кур'єрська доставка: 100 грн
        - `flatrate_2---0` — Резервування у магазині: 0 грн
        - `flatrate_7---0` — Доставка за межі України: 700 грн

        **Рекомендований метод для AI агента:** `flatrate_10---0` (Нова Пошта).

        **`delivery_country: "804"`** — числовий код України (ISO 3166-1 numeric).
      operationId: getCheckoutData
      responses:
        "200":
          description: Дані для оформлення замовлення
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CheckoutData"

  /api/cart/countries:
    get:
      tags: [Замовлення]
      summary: Список країн для доставки
      description: |
        Повертає список країн з числовими кодами (ISO 3166-1 numeric).
        Україна: `country_id: "804"`.
        Використовується для вибору країни при оформленні замовлення.
        `country_id` — рядок, не число.
      operationId: getCountries
      responses:
        "200":
          description: Список країн
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Country"
              example:
                - country_id: "804"
                  name: Україна
                - country_id: "616"
                  name: Poland
                - country_id: "276"
                  name: Germany

  /api/cart/order/place:
    post:
      tags: [Замовлення]
      summary: Розмістити замовлення
      description: |
        Оформлює замовлення з товарів поточного кошика.

        **Для AI агента:**
        - Обов'язковий лише `phone` — менеджер зателефонує для підтвердження.
        - Всі інші поля (`city`, `street1`, `postal_code` тощо) — опціональні,
          передавати `null` якщо юзер не вказав.
        - Завжди передавати `payment_method: "cod"` (накладений платіж).
        - Завжди додавати в `comments`: `"Замовлення оформлено через AI агента"`.
          Якщо юзер теж залишив коментар — об'єднати через кому.
        - `country_id: 804` — числовий код України (integer, не string).
        - `shipping_method` — ключ з `shipping_methods.options` в `/api/cart/checkout`.
          Рекомендовано: `"flatrate_10---0"` (Нова Пошта).
        - `shipping_cost` — вартість доставки з `shipping_methods.rates`.
        - `ptamt: 0` — бонусні бали не використовуються.

        При успіху повертає `order_id` і `msg` з підтвердженням.
        При помилці HTTP статус 4xx з JSON тілом помилки.
      operationId: placeOrder
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PlaceOrderRequest"
            example:
              first_name: Олена
              last_name: Петренко
              phone: "380671234567"
              city: Київ
              postal_code: "01001"
              country_id: 804
              shipping_method: flatrate_10---0
              shipping_cost: 90
              street1: Відділення №5
              comments: Замовлення оформлено через AI агента
              payment_method: cod
              ptamt: 0
      responses:
        "200":
          description: Замовлення успішно розміщено
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PlaceOrderResponse"
              example:
                success: true
                order_id: "283730"
                status: pending
                msg:
                  - p: "Найближчим часом ми його обробимо."

components:
  schemas:
    # ── Каталог ───────────────────────────────────────────────────────────────
    SearchResultItem:
      type: object
      description: |
        Товар у результатах пошуку. Ігноруй елементи де є поле `class`.
      properties:
        nid:
          type: string
          description: ID товару. Відсутнє у службовому елементі.
          example: "1818"
        value:
          type: string
          description: Артикул (SKU). Порожній рядок у службовому елементі.
          example: "64200003"
        title:
          type: string
          description: Назва товару або "Шукати більше"
          example: Сукня в горох з рукавом
        image:
          type: string
          format: uri
          description: URL зображення. Відсутнє у службовому елементі.
        url:
          type: string
          format: uri
          description: Повний URL товару або пошукової видачі
        class:
          type: string
          description: |
            Присутнє лише в останньому елементі.
            `"autocomplete-more"` = не товар, ігноруй.
          example: autocomplete-more

    # ── Категорії ─────────────────────────────────────────────────────────────

    Category:
      type: object
      required: [tid, tname, url_alias, depth]
      properties:
        tid:
          type: string
          description: ID категорії (string, не integer)
          example: "5"
        tname:
          type: string
          description: Назва категорії (мова залежить від локалі)
          example: Сукні
        tdesc:
          type: string
          description: HTML-опис з тегом `<h1>` (мова залежить від локалі)
          example: <h1>Купити модні сукні</h1>
        tphoto:
          type: string
          format: uri
          description: URL фото категорії
        parent_name:
          type: string
          nullable: true
          description: |
            Назва батьківської категорії. **Завжди російською** незалежно від локалі.
            `null` для кореневих категорій.
          example: Платья
        url_alias:
          type: string
          description: |
            Відносний шлях. Повний URL = `https://ladylike.ua/` + `url_alias`.
            З `/uk` сервером містить `uk/` префікс.
          example: uk/Platia
        depth:
          type: integer
          description: Рівень вкладеності. 0 — кореневий, 1 — підкатегорія, 2 — під-підкатегорія.
          example: 0

    # ── Товар у каталозі ──────────────────────────────────────────────────────

    CatalogProduct:
      type: object
      required: [nid, node_title, price, url_alias, field_image_cache_fid]
      description: |
        Товар у списку каталогу. Для повних деталей (розміри, склад, галерея)
        використовуй `/api/app/view/node_json/default?args={nid}`.
      properties:
        nid:
          type: string
          example: "9879"
        node_title:
          type: string
          description: Назва товару (мова залежить від локалі)
          example: Майка жіноча біла
        price:
          type: string
          description: Поточна ціна в гривнях (без десяткових знаків)
          example: "410"
        list_price:
          type: string
          description: |
            Базова ціна. Якщо `price` = `list_price` — знижки немає.
            При знижці обидва рівні знижковій ціні, оригінальна — в `old_price`.
          example: "410"
        price_sign:
          type: string
          description: Валюта
          example: " грн"
        url_alias:
          type: string
          description: |
            Відносний шлях. Повний URL = `https://ladylike.ua/` + `url_alias`.
            З `/uk` сервером містить `uk/` префікс.
          example: uk/Bluzy/Bluzy-s-korotkym-rukavom/Majky/Majka-zhenskaia-belaia
        field_image_cache_fid:
          type: string
          format: uri
          description: Основне фото (розмір `product_list`)
        field_image_cache_fid_1:
          type: string
          format: uri
          description: Мобільне фото (`product_list_m`)
        field_image_cache_fid_2:
          type: string
          format: uri
          description: Фото для віджету (`product_list_widget`)
        uc_product_stock_customer_vw_stock_level:
          type: string
          description: Кількість одиниць на складі по всіх розмірах
          example: "34"
        uc_product_stock_clothes_sizes_vw:
          type: string
          description: |
            Comma-separated внутрішні ID варіантів розміру.
            Кількість = кількість доступних розмірів.
          example: "3557000136,3557000140,3557000142"
        fast_shipping_info:
          type: string
          description: |
            Comma-separated прапорці швидкої доставки по розмірах.
            `"1"` = доступна, `"0"` = недоступна. Кількість = кількість розмірів.
          example: "1,1,1"
        total_sold:
          type: string
          description: Кількість проданих одиниць. Може бути відсутнє.
          example: "34"
        product_new:
          type: string
          description: |
            `"1"` = новинка. Присутнє в `page_4`/`page_3`.
            Відсутнє в `product_most_popular` та `product_popular`.
          example: "1"
        node_created:
          type: string
          description: Unix timestamp дати додавання
          example: "1778137396"
        node_created_month:
          type: string
          description: Місяць додавання у форматі YYYYMM. Присутнє в більшості ендпоінтів.
          example: "202605"
        node_created_year:
          type: string
          description: |
            Рік додавання. Присутнє в `product_most_popular` замість `node_created_month`.
          example: "2026"
        votingapi_cache_node_average_value:
          type: string
          description: Середній рейтинг (0–100)
          example: "99.7333"
        votingapi_cache_node_count_value:
          type: string
          description: Кількість оцінок
          example: "75"
        flagged_class:
          type: string
          description: |
            Стан у вішлісті для поточної сесії.
            `"flag-action"` = не у вішлісті, `"unflag-action"` = вже у вішлісті.
          enum: [flag-action, unflag-action]
          example: flag-action
        flag_content_content_id:
          type: string
          description: |
            Дублює `nid`. Присутнє лише в `product_popular`. Службове поле.
          example: "3234"
        old_price:
          type: string
          description: Оригінальна ціна до знижки. Присутнє лише при активній акції.
          example: "1100"
        discount_percent:
          type: string
          description: Знижка у відсотках. Присутнє лише при активній акції.
          example: "34"
        kit_old_price:
          type: string
          description: Оригінальна ціна комплекту. Присутнє при знижці.
          example: "1100"
        kit_discount_percent:
          type: string
          description: Знижка комплекту у відсотках. Присутнє при знижці.
          example: "34"
        uc_sales_planning_activation:
          type: string
          description: Unix timestamp початку акції. Присутнє при знижці.
          example: "1779118205"
        uc_sales_planning_expiration:
          type: string
          description: Unix timestamp закінчення акції. Присутнє при знижці.
          example: "1873812605"
        uc_sales_planning_activation_day:
          type: string
          description: Дата початку акції YYYYMMDD. Присутнє при знижці.
          example: "20260518"

    # ── Пагінація ─────────────────────────────────────────────────────────────

    CatalogPage:
      type: object
      properties:
        items:
          type: array
          items:
            $ref: "#/components/schemas/CatalogProduct"
        h1:
          type: string
          description: |
            Назва категорії або "Все"/"Скидки". Може бути російською (особливість бекенду).
            Порожній рядок коли категорія не задана.
          example: ""
        resultCount:
          type: integer
          description: Кількість товарів на поточній сторінці
          example: 40
        productCount:
          type: string
          description: Загальна кількість товарів (тип string, не integer)
          example: "2525"
        currentPage:
          type: integer
          nullable: true
          description: |
            Поточна сторінка. `0` для `page_4`/`page_3`.
            `null` для `product_most_popular`, `product_popular`, `sale_new`.
          example: 0
        pageCount:
          type: integer
          description: |
            Кількість сторінок від API. **Увага:** реальна кількість = `pageCount + 1`.
          example: 63
        lang_pref:
          type: string
          description: Мовний префікс. `"uk/"` або `""`. Службове поле.
          example: uk/

    # ── Фільтри ───────────────────────────────────────────────────────────────

    FilterGroup:
      type: object
      description: Група фільтрів каталогу
      properties:
        id:
          type: string
          description: |
            Внутрішній ID групи. Маппінг на query param:
            `pattr_1` → `pattr_size`,
            `field_color_value_many_to_one` → `field_color`,
            `field_fabric_value_many_to_one` → `field_fabric`,
            `field_fabric_pattern_value_many_to_one` → `field_fabric_pattern`,
            `field_fabric_warm_value_many_to_one` → `field_fabric_warm`,
            `field_features_value_many_to_one` → `field_features`,
            `field_fit_value_many_to_one` → `field_fit`,
            `store_id` → `store_id`
          example: pattr_1
        label:
          type: string
          description: Назва групи фільтру. Порожній рядок для службових груп.
          example: Розмір
        options:
          type: array
          description: Список значень фільтру. Порожній масив для службових груп.
          items:
            $ref: "#/components/schemas/FilterOption"

    FilterOption:
      type: object
      required: [id, name]
      properties:
        id:
          description: |
            ID значення для передачі у query param. Може бути string або integer.
            Використовуй як: `field_color[{id}]=true` або `store_id={id}`.
          example: "90"
          oneOf:
            - type: string
            - type: integer
        name:
          type: string
          description: Назва для відображення
          example: чорний
        hex:
          type: string
          description: HEX-код кольору. Присутнє лише для фільтру `field_color`.
          example: "#000000"

    # ── Хайлайти ──────────────────────────────────────────────────────────────

    CategoryHighlight:
      type: object
      description: |
        Готовий фільтр-посилання. Для отримання товарів передай поля з `filter`
        як query params в `/api/view/clothes/page_4`.
      properties:
        name:
          type: string
          description: Назва (мова залежить від локалі)
          example: Висока посадка
        filter:
          type: object
          nullable: true
          description: |
            Один query param для фільтрації каталогу.
            Можливі ключі: `field_fit`, `field_features`, `field_fabric`,
            `field_fabric_pattern`, `pattr_size`.
            `null` якщо хайлайт веде на підрозділ без фільтру.
          additionalProperties:
            type: string
          example:
            field_fit: "184172"
        tid:
          type: integer
          description: ID батьківської категорії
          example: 3
        img_url:
          type: string
          format: uri
          description: Велике зображення
        img_small_url:
          type: string
          format: uri
          description: Мале зображення (розмір cart)
        img_66_99_url:
          type: string
          format: uri
          description: Мініатюра 66×99px
        path:
          type: string
          description: Відносний шлях без локалі
          example: Briuky/field_fit=184172/filter
        cat_url:
          type: string
          description: Шлях з локаллю (`/uk/...` або `/...`)
          example: /uk/Briuky/field_fit=184172/filter

    CategoryShortcut:
      type: object
      description: Пряме посилання на категорію (числові ключі в `/topsearch`)
      properties:
        tid:
          type: string
          description: ID категорії
          example: "5"
        name:
          type: string
          description: Назва категорії
          example: Сукні
        img_url:
          type: string
          format: uri
          description: Зображення категорії
        cat_url:
          type: string
          description: Шлях з локаллю
          example: /uk/Platia

    # ── Банер ─────────────────────────────────────────────────────────────────

    Banner:
      type: object
      required: [image, start, end]
      properties:
        image:
          type: string
          format: uri
          description: URL зображення банера
          example: https://ladylike.ua/uk/f/valentines_day_2026_slim.jpg
        start:
          type: string
          description: Unix timestamp початку показу
          example: "1770760800"
        end:
          type: string
          description: Unix timestamp кінця показу
          example: "1771192800"

    # ── Відгуки ───────────────────────────────────────────────────────────────

    Review:
      type: object
      properties:
        title:
          type: string
          description: Заголовок відгуку або ім'я покупця
          example: Ірина, Київ
        text:
          type: string
          description: Текст відгуку
          example: Брюки сподобались. Тканина приємна і тепла.
        user_url:
          type: string
          description: Відносний шлях профілю покупця
          example: /uk/user/16140
        user_picture:
          type: string
          format: uri
          description: URL аватара покупця
        node_url:
          type: string
          description: Відносний шлях товару
          example: /uk/Briuky/Briuky-chernye-sherstianye-plotnye
        nid:
          type: string
          description: ID товару
          example: "8400"
        node_type:
          type: string
          description: Тип вузла. Завжди `"clothes"`.
          example: clothes
        product_image:
          type: string
          format: uri
          description: URL зображення товару (66×99px)

    # ── Товар ─────────────────────────────────────────────────────────────────
    ProductDetail:
      type: object
      description: |
        Повна інформація про товар. Звичайний товар і елемент комплекту мають
        однакову базову структуру. Комплект додає поля `type_2`, `title_1`,
        `field_kit_video_fid`, `node_uc_product_kits_nid`, `sell_price`.

        Відповідь також містить службові поля які слід ігнорувати:
        `node_vid`, `active_price`, `type`, `ops`, `votingapi_cache_*`,
        `node_data_field_*`, `uc_sales_planning_type`.
      properties:
        nid:
          type: string
          example: "9879"
        node_type:
          type: string
          description: Тип вузла. Завжди `"clothes"`.
          example: clothes
        type_1:
          type: string
          description: Тип вузла (дублює `node_type`). Завжди `"clothes"`.
          example: clothes
        type_2:
          type: string
          description: Присутнє лише для комплектів. Значення `"Набор товаров"`.
          example: Набор товаров
        title:
          type: string
          description: Назва товару (мова залежить від локалі)
          example: Майка жіноча біла
        body:
          type: string
          description: Опис товару (мова залежить від локалі)
        field_title_ua_value:
          type: string
          description: Назва українською. Присутнє з `/uk` локаллю.
        field_description_ua_value:
          type: string
          description: Опис українською. Присутнє з `/uk` локаллю.
        title_1:
          type: string
          description: Назва окремого предмету в комплекті. Лише для kit.
        field_title_ua_value_1:
          type: string
          description: Українська назва предмету в комплекті. Лише для kit.
        active_real_price:
          type: string
          description: Поточна ціна зі знижкою якщо є акція
          example: "410.00000"
        uc_products_sell_price:
          type: string
          description: Оригінальна ціна без знижки
          example: "1100.00000"
        sell_price:
          type: string
          description: Оригінальна ціна. Лише для kit елементів.
          example: "1700"
        discount_amount:
          type: string
          description: |
            Сума знижки в гривнях. Порожній рядок якщо немає.
            Стара ціна = parseFloat(active_real_price) + parseFloat(discount_amount).
          example: "378"
        discount_percent:
          type: string
          description: Відсоток знижки. Порожній рядок якщо немає.
          example: "34"
        activation:
          type: string
          description: Unix timestamp початку акції. Порожній рядок якщо немає.
          example: "1779129005"
        expiration:
          type: string
          description: Unix timestamp закінчення акції. Порожній рядок якщо немає.
          example: "1873823405"
        uc_sales_planning_activation:
          type: string
          nullable: true
          description: Unix timestamp початку акції (може бути null)
        uc_sales_planning_expiration:
          type: string
          nullable: true
          description: Unix timestamp закінчення акції (може бути null)
        uc_sales_planning_price:
          type: string
          nullable: true
          description: Знижкова ціна з п'ятьма знаками (може бути null)
        value:
          type: string
          description: |
            Рейтинг 0–100. Може бути дробовим: `"67.5"`, `"100"`.
          example: "100"
        value_1:
          type: string
          description: Кількість оцінок
          example: "61"
        stock_group_concat:
          type: string
          description: |
            Розміри з кількістю на складі: `"36 (13), 38 (0), 40 (10)"`.
            0 = немає в наявності. Розмір "01" — службовий, ігнорувати.
          example: "36 (2), 38 (0), 40 (0)"
        clothes_size_group_concat_vw:
          type: string
          description: Доступні розміри через кому. Порожній рядок якщо немає жодного.
          example: "36, 38, 40"
        uc_product_stock_concat:
          type: string
          description: Кількість по розмірах comma-separated
          example: "2,0,0"
        uc_product_stock_clothes_sizes:
          type: string
          description: Comma-separated внутрішні ID варіантів (всі розміри)
          example: "21181008936,21181008938,21181008940"
        uc_product_stock_clothes_sizes_vw:
          type: string
          nullable: true
          description: |
            Comma-separated внутрішні ID варіантів (лише доступні).
            Може бути `null` якщо жоден розмір недоступний.
          example: "21181008936"
        field_image_cache_fid:
          type: array
          description: Галерея зображень
          items:
            type: object
            properties:
              url:
                type: string
                format: uri
                description: Середній розмір (`product`)
              url_big:
                type: string
                format: uri
                description: Повний розмір (`product_full`)
        field_video_fid:
          type: string
          description: URL відео товару (.mp4). Порожній рядок якщо немає.
        field_kit_video_fid:
          type: string
          description: URL відео комплекту (.mp4). Лише для kit.
        model_1:
          type: string
          description: Артикул (SKU). Використовується в `/amp/stock/info/{model}`.
          example: "35570001"
        uc_products_model:
          type: string
          description: Дублює `model_1`. Службове.
        node_uc_product_kits_nid:
          type: string
          description: ID вузла комплекту. Лише для kit.
          example: "11135"
        node_uc_product_kits_vid:
          type: string
          description: Дублює `node_uc_product_kits_nid`. Службове. Лише для kit.
          example: "11135"
        node_uc_product_kits_type:
          type: string
          description: Тип вузла комплекту. Лише для kit. Завжди `"product_kit"`.
          example: product_kit
        field_fabric_value:
          type: string
          description: Тип тканини. `-1` якщо не вказано.
          example: Бавовна
        field_makeup_value:
          type: string
          description: Склад тканини
          example: 60% бавовна, 40% віскоза
        field_fabric_type_ua_value:
          type: string
          description: Склад тканини українською (дублює `field_makeup_value`)
        field_fabric_stretch_value:
          type: string
          description: Розтяжність тканини. Порожній рядок якщо не вказана.
          example: Не тягнеться
        field_size_matching_value:
          type: string
          description: Відповідність розміру. Порожній рядок якщо не вказана.
          example: Точно
        field_color_value:
          type: string
          description: Колір з `|` роздільником. Брати текст до першого `|`.
          example: бежевий|
        field_color_value_1:
          type: string
          description: ID кольору (відповідає ID у фільтрах каталогу). `-1` якщо не вказано.
          example: "82"
        field_features_value:
          type: string
          description: Особливості крою через `|`. Розбити і відфільтрувати порожні.
          example: З кишенями|З прямим кроєм|На резинці|
        field_fit_value:
          type: string
          description: Посадка. Порожній рядок якщо не вказана.
          example: Висока
        field_belt_value:
          type: string
          description: Пояс. Порожній рядок якщо немає.
          example: з поясом
        field_lining_value:
          type: string
          description: Підкладка. Порожній рядок або "В наявності".
        field_zipper_value:
          type: string
          description: Застібка. Порожній рядок якщо немає.
          example: спереду
        field_fabric_pattern_value:
          type: string
          description: Візерунок тканини. Порожній рядок якщо не вказаний.
          example: однотонна
        field_wash_value:
          type: string
          description: Інструкції по догляду текстом. Порожній рядок якщо немає.
        field_wash_values:
          description: Інструкції по догляду з піктограмами. `null` якщо не вказані.
          nullable: true
          allOf:
            - $ref: "#/components/schemas/WashValues"
        uc_term_fields_data:
          type: string
          nullable: true
          description: |
            JSON-рядок з мірками по розмірах, або рядок `"null"` (не JSON null).
            Клієнт має перевіряти: `value === "null" ? null : JSON.parse(value)`.
            Структура: `{ tid: { vid: { oid: { measure_name: {value, title}, name, ... } } } }`
            Набір мір залежить від типу одягу:
            - Сукні/топи: `dress_chest_length`, `dress_waist_width`, `blouse_short_thigh_width`
            - Брюки: `pants_length`, `pants_thigh_length`, `dress_waist_width`, `pants_middle_seam`
            - Жилети: `vest_length`, `vest_short_sleeve_chest_length`, `jacket_thigh_width`
        taxonomy_terms:
          type: array
          items:
            $ref: "#/components/schemas/TaxonomyTerm"
        breadcrumbs:
          type: array
          description: |
            Масив масивів шляху категорій. Зазвичай один внутрішній масив.
            `categoryTid` = `breadcrumbs[0][last].tid`.
          items:
            type: array
            items:
              $ref: "#/components/schemas/BreadcrumbItem"
        flag_content_content_id:
          nullable: true
          description: Службове поле вішліста. Зазвичай `null`.

    WashValues:
      type: object
      description: Інструкції по догляду з піктограмами
      properties:
        values:
          type: object
          description: Числові ID → текстовий опис інструкції
          additionalProperties:
            type: string
          example:
            "11": Одяг можна прати в машинці (делікатний режим), до 30°С
            "29": Не можна прасувати
        images:
          type: object
          description: Числові ID → відносний шлях піктограми
          additionalProperties:
            type: string
          example:
            "11": /themes/ampu/img/wash/30.jpg
            "29": /themes/ampu/img/wash/no_press.jpg

    TaxonomyTerm:
      type: object
      properties:
        tid:
          type: string
          example: "25"
        name:
          type: string
          description: Назва (мова залежить від локалі)
          example: Майки
        vid:
          type: string
          description: |
            ID словника:
            `"1"` = категорія (Жіночий одяг),
            `"3"` = акція (Знижки, Останні розміри),
            `"4"` = колекція (Весна-Літо, Осінь-Зима),
            `"7"` = новинки,
            `"9"` = властивості (Літні, Міді),
            `"10"` = подія/стиль (Офісний, Casual)
          example: "1"
        vocabulary:
          type: string
          description: Назва словника
          example: Жіночий одяг
        url:
          type: string
          description: Відносний шлях (з або без `/uk/` залежно від локалі)
          example: /uk/Bluzy/Bluzy-s-korotkym-rukavom/Majky

    BreadcrumbItem:
      type: object
      properties:
        tid:
          type: string
          example: "24"
        name:
          type: string
          example: Блузи з коротким рукавом
        url:
          type: string
          example: /uk/Bluzy/Bluzy-s-korotkym-rukavom

    ValuesListResponse:
      type: object
      description: Загальна структура відповіді для color_block та relative_clothes
      properties:
        items:
          type: array
          items:
            type: object
            properties:
              values:
                type: array
                items:
                  $ref: "#/components/schemas/CatalogCardItem"
        h1:
          type: string
          description: Назва товару (може бути російською)
        resultCount:
          type: integer
        productCount:
          nullable: true
          description: Завжди `null`
        currentPage:
          nullable: true
          description: Завжди `null`
        pageCount:
          type: integer
          description: Завжди `0`
        lang_pref:
          type: string
          example: uk/

    CatalogCardItem:
      type: object
      description: Спрощена картка товару у списках (варіанти кольору, схожі)
      properties:
        nid:
          type: string
          example: "11234"
        field_image_cache_fid:
          type: string
          format: uri
          description: URL мініатюри (`uc_thumbnail`)
        field_image_cache_fid_alt:
          type: string
          description: Alt-текст зображення
        field_image_cache_fid_title:
          type: string
          description: Title зображення
        price:
          type: string
          description: Поточна ціна
          example: "1100"
        old_price:
          type: string
          description: Стара ціна. Присутнє якщо є знижка.
          example: "1600"
        discount_percent:
          type: string
          description: Відсоток знижки. Присутнє якщо є знижка.
          example: "27"
        price_sign:
          type: string
          example: " грн"
        url_alias:
          type: string
          example: uk/Kofty/Kofta-tepla-melanzheva-bezheva-zi-stijkoiu
        flagged_class:
          type: string
          enum: [flag-action, unflag-action]
        flagged_token:
          type: string

    RelatedProductItem:
      type: object
      description: Товар у списку «часто купують разом»
      properties:
        nid:
          type: string
          example: "11056"
        img_src:
          type: string
          format: uri
          description: URL мініатюри (`uc_thumbnail`)
        url_alias:
          type: string
          example: uk/Platia/Suknia-bilo-bezheva
        price:
          type: integer
          description: Ціна (integer, не string)
          example: 1950
        price_sign:
          type: string
          example: " грн"

    StoreAvailability:
      type: object
      description: Наявність товару в одному магазині
      properties:
        store_id:
          type: string
          description: ID магазину
          example: "2"
        store_name:
          type: string
          example: пр-кт Берестейський (Перемоги), 15
        store_city:
          type: string
          example: Київ
        store_link:
          type: string
          description: Відносний шлях сторінки магазину
          example: /uk/node/29
        store_map:
          type: string
          description: Відносний шлях схеми магазину
          example: /f/reserve_pobedi_2.jpg
        sizes:
          type: array
          items:
            $ref: "#/components/schemas/StoreSize"

    StoreSize:
      type: object
      properties:
        size-class:
          type: string
          enum: [active, inactive]
          description: |
            `"active"` — є в наявності.
            `"inactive"` — немає, можна замовити з доставкою.
          example: active
        size-option:
          type: string
          description: Внутрішній ID варіанту розміру
          example: "3557000136"
        delivery:
          type: string
          description: |
            `"0"` — є в наявності.
            `"1-2"` — доставка між магазинами 1-2 дні.
          example: "0"
        size-text:
          type: string
          description: Розмір для відображення
          example: "36"

    ProductReview:
      type: object
      properties:
        cid:
          type: string
          description: ID коментаря
          example: "325"
        nid:
          type: string
          description: ID товару
          example: "9879"
        subject:
          type: string
          description: Заголовок відгуку
          example: мені подобається все .
        comment:
          type: string
          description: Текст відгуку
        sizematch:
          type: string
          nullable: true
          description: Відповідність розміру. Може бути `null`.
        timestamp:
          type: string
          description: Unix timestamp дати публікації
          example: "1389804698"
        name:
          type: string
          description: Ім'я користувача
          example: mrverhola
        uid:
          type: string
          description: ID користувача
          example: "1136"
        fivestar_rating:
          type: string
          description: Оцінка 0–100 (100 = 5 зірок)
          example: "100"
        depth:
          type: integer
          description: Рівень вкладеності. `0` = кореневий відгук.
          example: 0
        pid:
          type: string
          description: ID батьківського коментаря. `"0"` = кореневий.
          example: "0"
        links:
          type: object
          description: Службові посилання. Містить `comment_reply` з href для відповіді.
          properties:
            comment_reply:
              type: object
              properties:
                title:
                  type: string
                  example: відповісти
                href:
                  type: string
                  example: comment/reply/1428/325

    # ── Кошик і Замовлення ────────────────────────────────────────────────────
    AppSettings:
      type: object
      properties:
        languages:
          type: array
          items:
            type: object
            properties:
              langcode:
                type: string
                example: uk
        shipping:
          type: array
          description: |
            Масив з двох елементів:
            - `[0]`: `free_shipping_min_total` і `price: 0`
            - `[1]`: `standard_price`
          items:
            type: object
            properties:
              free_shipping_min_total:
                type: integer
                description: Мінімальна сума замовлення для безкоштовної доставки
                example: 2000
              price:
                type: integer
                description: Ціна безкоштовної доставки (завжди 0)
                example: 0
              standard_price:
                type: integer
                description: Стандартна ціна доставки в гривнях
                example: 60
        return:
          type: object
          properties:
            max_days:
              type: integer
              description: Максимальна кількість днів для повернення
              example: 30
        liqpay:
          type: object
          description: LiqPay конфігурація по валютах. Службове поле.
          additionalProperties:
            type: object
            properties:
              currency:
                type: string
              merchant_id:
                type: string
        order_statuses:
          type: array
          description: Всі можливі статуси замовлень
          items:
            $ref: "#/components/schemas/OrderStatus"
        stores:
          type: object
          description: |
            Всі магазини (об'єкт з числовими ключами = store_id).
            `disabled: "1"` = магазин закрито, не показувати.
            `latitude/longitude: "0.000000"` = координати не вказані.
          additionalProperties:
            $ref: "#/components/schemas/Store"

    OrderStatus:
      type: object
      properties:
        title:
          type: string
          description: Назва статусу українською
          example: В обробці
        state:
          type: string
          description: |
            Група статусу:
            `in_checkout` — у кошику,
            `post_checkout` — після оформлення,
            `payment_received` — оплата отримана,
            `completed` — завершено,
            `canceled` — скасовано,
            `pos_canceled`, `pos_in_progress`, `pos_completed` — POS статуси
          example: post_checkout
        weight:
          type: string
          description: Порядок сортування (рядок, може бути від'ємним)
          example: "0"
        locked:
          type: string
          description: '`"1"` = системний статус, не змінюється вручну'
          example: "1"
        id:
          type: string
          description: Ідентифікатор статусу
          example: pending

    Store:
      type: object
      properties:
        store_id:
          type: string
          example: "7"
        store_name:
          type: string
          example: ТЦ Дарниця
        store_address:
          type: string
          example: "пр-кт возз'єднання, 2/1"
        store_city:
          type: string
          example: Київ
        store_state:
          type: string
          description: Область. Може бути порожнім рядком.
        store_zip:
          type: string
          description: Поштовий індекс або службовий код. Може бути порожнім.
        store_country:
          type: string
          description: Країна. Може бути порожнім рядком.
        store_phone:
          type: string
          example: "(044) 236-49-31"
        store_fax:
          type: string
          description: Службове поле (може містити ПІБ відповідального).
        disabled:
          type: string
          description: '`"0"` = активний, `"1"` = закрито'
          enum: ["0", "1"]
          example: "0"
        latitude:
          type: string
          description: Широта. `"0.000000"` = не вказана.
          example: "50.442430"
        longitude:
          type: string
          description: Довгота. `"0.000000"` = не вказана.
          example: "30.624120"

    # ── Кошик ─────────────────────────────────────────────────────────────────

    AddToCartSuccess:
      type: object
      properties:
        cart_id:
          type: string
          description: ID кошика (MD5 хеш сесії)
          example: 24d4b9c802405d50fbe1e0fdd97d381d
        cart_item_id:
          type: string
          description: ID позиції в кошику. Використовується в `/amp/cart/update` як `ci_id`.
          example: "221308"
        size:
          type: string
          description: Розмір у форматі EU
          example: 36 EU
        message:
          type: string
          description: Інформація про дату доставки
          example: Відправка сьогодні. Доставка у ваше відділення пошти - Субота, 23 Травень.

    CartError:
      type: object
      description: Помилка при додаванні товару. HTTP статус — 200 (не 4xx).
      properties:
        verifyErrors:
          type: object
          properties:
            name:
              type: string
              description: Назва поля з помилкою
              example: size
            message:
              type: string
              description: Текст помилки для відображення юзеру
              example: "😔 На жаль, розмір розпродано."

    CartData:
      type: object
      properties:
        items:
          type: array
          items:
            type: object
            properties:
              values:
                type: array
                description: Позиції кошика. Порожній масив якщо кошик порожній.
                items:
                  $ref: "#/components/schemas/CartItem"
        productCount:
          type: integer
          nullable: true
          description: Кількість одиниць товару. `null` якщо кошик порожній.
          example: 1
        total:
          type: string
          nullable: true
          description: |
            Загальна сума у форматі `"410,00 грн"`. `null` якщо кошик порожній.
            Десятковий роздільник — кома, не крапка.
          example: "410,00 грн"
        deliveryText:
          type: string
          description: |
            Промо-текст про доставку. Може містити HTML розмітку.
            Зазвичай порожній рядок. При великій сумі замовлення може містити
            повідомлення про бонус (наприклад знижкову карту).
          example: ""

    CartItem:
      type: object
      properties:
        cart_id:
          type: string
          description: ID кошика
          example: 24d4b9c802405d50fbe1e0fdd97d381d
        cid:
          type: string
          description: |
            ID позиції в кошику. Використовується в:
            - `POST /amp/cart/update` як `ci_id`
          example: "221308"
        nid:
          type: string
          description: ID товару
          example: "9879"
        qty:
          type: string
          description: Кількість одиниць (рядок, не число)
          example: "1"
        title:
          type: string
          description: Назва товару
          example: Майка жіноча біла
        price:
          type: string
          description: Ціна за одиницю у форматі `"410,00 грн"` (кома як роздільник)
          example: "410,00 грн"
        price_old:
          type: string
          description: Стара ціна якщо є знижка. Порожній рядок якщо немає.
          example: ""
        price_qty:
          type: string
          description: Загальна ціна позиції (ціна × qty)
          example: "410,00 грн"
        image:
          type: string
          format: uri
          description: URL мініатюри товару (`uc_thumbnail`)
        url:
          type: string
          description: Відносний шлях сторінки товару
          example: /uk/Bluzy/Bluzy-s-korotkym-rukavom/Majky/Majka-zhenskaia-belaia
        attrs:
          type: string
          description: Атрибути розміру у читабельному форматі
          example: 36 EU (42 укр.) S
        colors:
          type: string
          description: Колір товару
          example: Білий
        size:
          type: string
          description: Числова частина розміру
          example: "36"
        sku:
          type: string
          description: Внутрішній ID варіанту розміру
          example: "3557000136"

    # ── Замовлення ────────────────────────────────────────────────────────────

    CheckoutData:
      type: object
      properties:
        status:
          type: string
          description: Статус відповіді. Завжди `"ok"`.
          example: ok
        order_last:
          type: object
          nullable: true
          description: |
            Дані останнього замовлення прив'язаного до поточного session cookie.
            Присутній якщо в цій сесії вже було замовлення.

            **⚠️ AI агент НЕ повинен використовувати ці дані автоматично.**
            Завжди запитувати у юзера в чаті — мінімум `phone`.
          properties:
            order_id:
              type: string
              example: "283717"
            uid:
              type: string
              description: ID юзера. `"0"` = анонімний.
              example: "0"
            order_status:
              type: string
              description: Статус останнього замовлення
              example: not_answer
            order_total:
              type: string
              description: Сума замовлення з п'ятьма знаками після коми
              example: "899.00000"
            product_count:
              type: string
              example: "1"
            primary_email:
              type: string
              description: Email. Зазвичай порожній для анонімної сесії.
            delivery_first_name:
              type: string
            delivery_last_name:
              type: string
            delivery_phone:
              type: string
              description: Телефон у форматі `380XXXXXXXXX`
              example: "380967941952"
            delivery_company:
              type: string
            delivery_street1:
              type: string
            delivery_street2:
              type: string
            delivery_city:
              type: string
              example: Київ
            delivery_zone:
              type: string
              description: Службове поле. Зазвичай `"0"`.
            delivery_postal_code:
              type: string
            delivery_country:
              type: string
              description: Числовий код країни. `"804"` = Україна.
              example: "804"
            billing_first_name:
              type: string
            billing_last_name:
              type: string
            billing_phone:
              type: string
            billing_company:
              type: string
            billing_street1:
              type: string
            billing_street2:
              type: string
            billing_city:
              type: string
            billing_zone:
              type: string
            billing_postal_code:
              type: string
            billing_country:
              type: string
              example: "804"
            payment_method:
              type: string
              description: Метод оплати попереднього замовлення. Може бути порожнім.
            data:
              type: string
              description: Службове поле з серіалізованими даними PHP. Ігнорувати.
            created:
              type: string
              description: Unix timestamp створення замовлення
              example: "1779434210"
            modified:
              type: string
              description: Unix timestamp останньої зміни
            host:
              type: string
              description: IP адреса. Службове поле.
            currency:
              type: string
              example: UAH
            scheduled_delivery_date:
              type: string
              description: Службове поле. Зазвичай `"0"`.
            np_sender_id:
              type: string
              description: Службове поле Нової Пошти. Зазвичай `"0"`.
            shipping_method:
              type: string
              description: Метод доставки попереднього замовлення
              example: flatrate_10---0
        base_fields:
          type: object
          description: Службове поле з метаданими форми. Для AI агента не потрібне.
        extra_fields:
          type: object
          description: |
            Службові додаткові поля замовлення. Для AI агента не потрібні.
            Містить: `ucxf_transport_name`, `ucxf_branch_number_to`,
            `ucxf_transport_id`, `ucxf_branch_number_from`,
            `ucxf_middle_name`, `ucxf_reserve_in_store`.
        shipping_methods:
          type: object
          properties:
            options:
              type: object
              description: |
                Методи доставки `{ key: label }`.
                Ключ передається в `placeOrder` як `shipping_method`.
                Значення містить HTML-ентіті (`&#039;` = апостроф) — декодувати перед відображенням.
              additionalProperties:
                type: string
              example:
                flatrate_10---0: "Нова Пошта: 90,00 грн"
                flatrate_11---0: "Укрпошта: 55,00 грн"
                flatrate_12---0: "Кур&#039;єрська доставка: 100,00 грн"
                flatrate_2---0: "Зарезервувати у магазині (до 10 од.), м. Київ: 0,00 грн"
                flatrate_7---0: "Доставка за пределы Украины: 700,00 грн"
            rates:
              type: object
              description: "Вартість доставки `{ key: cost }` де cost — число (грн)"
              additionalProperties:
                type: number
              example:
                flatrate_10---0: 90
                flatrate_11---0: 55
                flatrate_12---0: 100
                flatrate_2---0: 0
                flatrate_7---0: 700
            options_ext:
              type: object
              description: |
                Розширені опції для деяких методів доставки. Службове поле.
                Наприклад для `flatrate_2---0` містить select для вибору магазину.

    Country:
      type: object
      properties:
        country_id:
          type: string
          description: Числовий код країни (ISO 3166-1 numeric). Рядок, не число.
          example: "804"
        name:
          type: string
          description: Назва країни (англійською, крім України)
          example: Україна

    PlaceOrderRequest:
      type: object
      required: [phone, payment_method]
      description: |
        Для AI агента обов'язковий лише `phone`.
        Всі інші поля — опціональні, передавати `null` якщо юзер не вказав.
        `comments` — завжди включати текст `"Замовлення оформлено через AI агента"`.
      properties:
        first_name:
          type: string
          nullable: true
          description: Ім'я отримувача
          example: Олена
        last_name:
          type: string
          nullable: true
          description: Прізвище отримувача
          example: Петренко
        phone:
          type: string
          description: |
            Телефон отримувача. **Єдине обов'язкове поле для AI агента.**
            Менеджер зателефонує для підтвердження замовлення.
            Формат: `380XXXXXXXXX` (без `+`, без пробілів).
          example: "380671234567"
        city:
          type: string
          nullable: true
          description: Місто доставки
          example: Київ
        postal_code:
          type: string
          nullable: true
          description: Поштовий індекс або номер відділення Нової Пошти
          example: "01001"
        country_id:
          type: integer
          nullable: true
          description: Числовий код країни (integer, не string). `804` = Україна.
          default: 804
          example: 804
        shipping_method:
          type: string
          nullable: true
          description: |
            Ключ методу доставки з `shipping_methods.options`.
            Рекомендовано для AI агента: `"flatrate_10---0"` (Нова Пошта).
          example: flatrate_10---0
        shipping_cost:
          type: number
          nullable: true
          description: Вартість доставки з `shipping_methods.rates`
          example: 90
        street1:
          type: string
          nullable: true
          description: Адреса вулиці або номер відділення пошти
          example: Відділення №5
        comments:
          type: string
          nullable: true
          description: |
            Коментар до замовлення.
            AI агент завжди додає: `"Замовлення оформлено через AI агента"`.
            Якщо юзер теж залишив коментар — об'єднати через кому.
          example: "Замовлення оформлено через AI агента"
        payment_method:
          type: string
          description: |
            Метод оплати. Для AI агента — завжди `"cod"` (накладений платіж).
            `"liqpay"` потребує редиректу в браузер — не використовувати.
          enum: [cod, liqpay]
          example: cod
        ptamt:
          type: integer
          description: Кількість бонусних балів для списання. Завжди `0` для AI агента.
          default: 0
          example: 0

    PlaceOrderResponse:
      type: object
      properties:
        success:
          type: boolean
          description: Завжди `true` при успіху
          example: true
        order_id:
          type: string
          description: |
            Номер замовлення. Показувати юзеру як підтвердження.
            Не міститься в `msg` — брати звідси.
          example: "283730"
        status:
          type: string
          description: |
            Початковий статус замовлення. Відповідає `id` з `order_statuses`
            в `/api/app/settings`. Зазвичай `"pending"`.
          example: pending
        msg:
          type: array
          description: |
            Масив повідомлень для відображення юзеру.
            Кожен елемент — об'єкт з HTML-тегом як ключем і текстом як значенням.
            Наприклад `{ "p": "Найближчим часом ми його обробимо." }`.
            Для відображення — збирати текст з усіх елементів масиву.
            Номер замовлення в `msg` не міститься — брати з поля `order_id`.
          items:
            type: object
            additionalProperties:
              type: string
          example:
            - p: "Найближчим часом ми його обробимо."
