Меню

Меню можно получить двумя способами. Разница существенная, выберите осознанно.

Витрина /menusНоменклатура /nomenclature
Что внутриМеню, собранное заведением для внешнего каналаПолный каталог товаров бренда
Названия, описания, картинкиОтдельные, под ваш каналВнутренние, как в системе заведения
ЦеныЦены витриныЦены точки
СоставТолько отобранные заведением позицииВсе товары, включая непродаваемые
Когда использоватьПо умолчаниюЕсли собираете витрину сами

Начинайте с витрины. К номенклатуре переходите, только если витрины не хватает.

Витрина должна быть выбрана

Оба метода работают только если заведение выбрало для вашего ключа внешнее меню (Интеграции → API-ключи). Иначе /menus вернёт 409 с просьбой обратиться в заведение.

Так сделано, чтобы цена в меню всегда совпадала с ценой заказа: без выбранной витрины непонятно, по какому прайсу считать, и вы показали бы одну сумму, а в кассу ушла бы другая.

Список витрин

GET /menus
{
  "menus": [
    { "id": 2, "name": "Мобильное приложение", "description": null, "updated_at": "2026-08-09 19:07:39" }
  ]
}

Ваш ключ, как правило, привязан к одной витрине — тогда в списке будет она одна. Так и должно быть: у заведения могут быть другие витрины (для агрегаторов доставки), и цены в них отличаются от ваших.

updated_at — когда витрину меняли последний раз. Удобно для решения, перезагружать меню или нет.

Витрина целиком

GET /menus/{id}?point_id={uuid}

point_id обязателен: от точки зависит стоп-лист.

{
  "id": 2,
  "name": "Мобильное приложение",
  "categories": [
    {
      "id": 1964,
      "name": "🥪 Сэндвичи и донеры",
      "order_number": 2,
      "image": "https://backend.mison.uz/uploads/menu/abc.webp"
    }
  ],
  "products": [
    {
      "product_id": 777,
      "category_id": 1964,
      "name": "Fanta 1 л",
      "description": "Освежающий газированный напиток со вкусом апельсина",
      "price": 12000,
      "weight": 1000,
      "unit": "мл",
      "order_number": 1,
      "image": "https://backend.mison.uz/uploads/products/xyz.webp",
      "calories": 48,
      "proteins": 0,
      "fat": 0,
      "carbohydrates": 12,
      "is_available": true,
      "available_quantity": null,
      "modifier_groups": [
        {
          "id": 9,
          "name": "Соусы",
          "min": 0,
          "max": 2,
          "required": false,
          "items": [
            { "product_id": 3884, "name": "Соус барбекю", "price": 2500, "min_amount": 0, "max_amount": 1 }
          ]
        }
      ]
    }
  ]
}

Поля товара

ПолеОписание
product_idИдентификатор товара. Его передаёте в заказе
category_idКатегория из categories
priceЦена в валюте заведения, целое число
weight / unitВес и единица измерения, могут быть null
imageГотовая ссылка на картинку или null
is_availablefalse — товар в стоп-листе, не показывайте его как доступный
available_quantityОстаток, если он ограничен. null — ограничения нет
modifier_groupsГруппы модификаторов, пустой массив если их нет

order_number — порядок сортировки, задан заведением. Соблюдайте его: заведение расставило позиции осознанно.

Модификаторы

Группа модификаторов — это выбор, который делает пользователь: соус, размер, добавка.

Поле группыОписание
minМинимум позиций к выбору. 0 — можно ничего не выбирать
maxМаксимум позиций. 0 — без ограничения
requiredtrue — без выбора заказ отправлять нельзя
itemsВарианты выбора

У варианта price — доплата за него, отдельной строкой в сумме заказа. min_amount / max_amount — сколько единиц одного варианта можно взять.

Группы без вариантов в ответе не приходят.

Номенклатура

GET /nomenclature?point_id={uuid}

Полный каталог бренда. Структура ответа такая же, как у витрины — categories и products с теми же полями, — но состав шире и названия внутренние.

{
  "categories": [{ "id": 38627, "name": "Напитки", "parent_id": null, "order_number": 1, "image": null }],
  "products": [
    {
      "product_id": 777,
      "category_id": 38627,
      "name": "Fanta 1 l",
      "price": 12000,
      "is_available": true,
      "modifier_groups": []
    }
  ]
}

Отличия от витрины:

  • у категорий есть parent_id — дерево может быть вложенным;
  • в списке есть товары, которые заведение не выставляет на продажу.

Цены здесь те же, что в вашей витрине: для товаров, которых в витрине нет, берётся цена точки. Это ровно те цены, по которым посчитается заказ.

Стоп-лист

GET /stop-list?point_id={uuid}

Позиции, которых сейчас нет или осталось ограниченное количество.

{
  "stop_list": [
    { "product_id": 777, "quantity": 0 },
    { "product_id": 783, "quantity": 3 }
  ]
}
quantityЗначение
0Товара нет. Заказ с ним будет отклонён
> 0Осталось столько единиц. Больше заказать нельзя

Товара нет в списке — ограничений нет.

Зачем отдельный метод

Меню тяжёлое и меняется редко, стоп-лист лёгкий и меняется в течение дня. Забирайте меню раз в час, стоп-лист — раз в минуту. Флаги is_available в меню тоже актуальны, но на момент запроса меню.

Кеширование

ЧтоКак часто обновлять
Витрина, номенклатураРаз в час, либо по изменению updated_at
Стоп-листРаз в 1–2 минуты
СправочникиРаз в сутки

Сервер отклонит заказ с позицией из стоп-листа, даже если ваш кеш устарел, — деньги пользователя не пострадают. Но лучше не доводить до отказа: пользователь уже собрал корзину.