POS API МойСклад — это набор розничных сущностей JSON API 1.2 для построения собственной кассы: точка продаж, кассовая смена, чеки продаж и возвратов, движения наличных. Разберём модель данных розницы, жизненный цикл смены и главную боль касс — работу офлайн с последующей синхронизацией.
Модель розницы в МойСклад
Розничный контур строится вокруг точки продаж и кассовой смены, внутри которой оформляются чеки. Основные сущности JSON API 1.2:
| Сущность | Назначение |
|---|---|
retailstore | Точка продаж: организация, склад, касса |
retailshift | Кассовая смена (открытие/закрытие) |
retaildemand | Розничная продажа (чек) |
retailsalesreturn | Возврат розничной продажи |
cashin / cashout | Внесение и выплата наличных |
Точка продаж связывает организацию (от чьего лица продажа), склад (откуда списывается товар) и кассу. Все чеки и движения денег привязываются к открытой смене этой точки.
access_token, те же правила фильтрации и пагинации, но со своей логикой смен и фискализации.Кассовая смена: открытие и закрытие
Продавать можно только в рамках открытой смены. Жизненный цикл прост, но требует строгого порядка:
- открываем смену —
POST /api/remap/1.2/entity/retailshiftс указанием точки продаж; - оформляем чеки и движения наличных внутри смены;
- закрываем смену — фиксируем итоги (выручка, количество чеков).
Открытая смена — это ещё и связка с ККТ: реальная касса открывает фискальную смену, а МойСклад ведёт учётную. Их состояния должны совпадать.
Оформление продажи и возврата
Чек — это retaildemand с позициями (positions), привязкой к смене и способом оплаты. В позициях указываются товар/модификация, количество, цена и скидки.
- оплата бывает наличными, картой, предоплатой и смешанной;
- списание товара со склада происходит по проведённому чеку;
- возврат оформляется
retailsalesreturnсо ссылкой на исходную продажу.
Пример минимального тела продажи:
{"retailShift":{"meta":{...}},"positions":[{"assortment":{"meta":{...}},"quantity":1,"price":150000}]}
Цена в JSON API 1.2 указывается в копейках (price: 150000 = 1500 руб). Это частый источник ошибок — не забывайте про множитель 100.
Движения наличных: внесение и выплата
Касса — это ещё и денежный ящик. Помимо чеков, в смене учитываются движения наличных, не связанные с продажей:
cashin— внесение (размен в начале смены, инкассация наоборот);cashout— выплата (выемка наличных, расходы).
Эти операции влияют на остаток в кассе и попадают в итоги смены. При закрытии смены сумма наличных должна сходиться: начальный остаток + продажи за наличные + внесения − выплаты − возвраты.
Офлайн-режим и синхронизация
Главная инженерная задача кассы — работа без интернета. Магазин не может останавливать продажи из-за сети, поэтому POS должен продавать офлайн и синхронизироваться при появлении связи.
| Данные | Стратегия |
|---|---|
| Товары, цены, штрихкоды | Кэш на устройстве, периодическое обновление |
| Остатки | Локальный расчёт, сверка при онлайне |
| Чеки | Локальная очередь, отправка в МойСклад пачками |
- каждому офлайн-чеку присваивайте локальный уникальный идентификатор для дедупликации;
- отправку делайте идемпотентной — повтор не должен создавать дубль продажи;
- обновление справочников — по изменённым записям (
filter=updated>...), а не полной выгрузкой.
Загрузка ассортимента и остатков
Кассе нужны товары с ценами, штрихкодами и остатками — и лучше одним запросом, а не по одной позиции. Для этого в JSON API 1.2 есть объединённая выборка entity/assortment, которая отдаёт товары, модификации, комплекты и услуги вместе.
GET /api/remap/1.2/entity/assortment?filter=stockStore=<склад точки>&limit=1000
- Штрихкоды — поле
barcodes, по нему касса ищет товар при сканировании; - Цены —
salePricesс типами цен, выбирайте нужный тип для розницы; - Остатки — параметр
stockStoreпривязывает остаток к складу точки продаж; - Пагинация — по 1000 записей через
limit/offset.
Полную выгрузку делайте редко (первичная загрузка на устройство), а инкрементальную — по фильтру измерённых записей. Так вы не упираетесь в лимиты частоты запросов и держите локальный кэш свежим.
Связь с фискализацией
Розничная продажа в России сопровождается фискальным чеком по 54-ФЗ. POS API отвечает за учётную часть, а пробитие чека — за ККТ и Фискальный API.
- оформляем
retaildemandв МойСклад; - отправляем данные чека на ККТ для фискализации;
- сохраняем фискальные реквизиты (ФН, ФД, ФП) рядом с продажей.
Важно не «пробить» чек дважды при повторной синхронизации — фискализация должна происходить один раз на продажу, с защитой от дублей на уровне локального идентификатора чека.
Итог
POS API — это розничная часть JSON API 1.2: точка продаж, смена, чеки продаж и возвратов, движения наличных. Ключевые сложности — строгий жизненный цикл смены, цены в копейках, устойчивая офлайн-работа с дедупликацией чеков и корректная связка с фискализацией по 54-ФЗ.
Мы разрабатываем кассовые и розничные интеграции: офлайн-режим с очередью синхронизации, обмен остатками и ценами, связку с ККТ и учётом в МойСклад. Спроектируем архитектуру, которая продаёт даже без сети и не создаёт дублей при восстановлении связи.
Частые вопросы
POS API — это отдельный API?
Нет, это розничная часть JSON API 1.2: сущности retailstore, retailshift, retaildemand и движения наличных. Авторизация и правила те же, что и в основном API.
Можно ли продавать без открытой смены?
Нет. Чеки и движения наличных оформляются только в рамках открытой кассовой смены конкретной точки продаж. На одной кассе одновременно активна одна смена.
В каких единицах указывается цена?
В копейках. Значение price 150000 означает 1500 рублей. Забытый множитель 100 — одна из самых частых ошибок интеграции.
Как оформить возврат?
Создать retailsalesreturn со ссылкой на исходную розничную продажу. Возврат влияет на остаток товара и на итоги кассовой смены.
Как касса работает без интернета?
POS кэширует товары, цены и штрихкоды на устройстве, продаёт офлайн, складывает чеки в локальную очередь и синхронизирует их с МойСклад пачками при появлении связи.
Как избежать дублей чеков при синхронизации?
Присваивайте каждому офлайн-чеку локальный уникальный идентификатор и делайте отправку идемпотентной, чтобы повторная синхронизация не создавала вторую продажу.
Как учитываются внесения и выплаты наличных?
Операциями cashin и cashout. Они влияют на остаток в денежном ящике и на итоги смены, которые сверяются при её закрытии.
POS API сам пробивает фискальный чек?
Нет. Он отвечает за учётную продажу, а фискализация по 54-ФЗ выполняется через ККТ и Фискальный API. Важно пробивать чек один раз на продажу.
Поможем с настройкой и поддержкой Для разработчиков
Поможем с настройкой, доработкой и поддержкой Для разработчиков.