Документация ·API
Открытый REST API
Через этот интерфейс работают кабинет, терминал и монитор смены. Для программы клиента есть ключ интеграции и четыре вызова — они описаны на странице «Интеграции», в разделе «Своя интеграция». Полное описание интерфейса — схема OpenAPI.
Адрес и версия
Точка входа — /api/v1. Несовместимые изменения выходят под новым номером версии, поведение /api/v1 не меняется.
Схема OpenAPI — по адресу /api/v1/openapi.json, без токена. По ней генерируют клиент или открывают интерфейс в Postman и Swagger UI.
Схема собирается из описаний маршрутов на сервере и всегда соответствует тому, что сервер принимает.
Аутентификация
Три вида входа, у каждого свой заголовок. Сеанс человека — Authorization: Bearer <JWT>. Терминал, монитор и агент печати — X-Device-Token, токеном, выданным при подключении кодом. Своя программа клиента — Authorization: Bearer zk_…, ключом интеграции. Каждый токен и ключ привязан к одной организации: данные других организаций по нему недоступны.
Паролей у сотрудников склада нет: в панель входят по коду или ссылке из письма, на терминал — бейджем или личным ключом.
Единый формат ошибки
Все отказы приходят в одном формате. code — код из таблицы ниже: по нему программа решает, что делать. message — объяснение по-русски, его можно показать человеку как есть. requestId — номер запроса: назовите его поддержке, и мы найдём причину.
{
"error": {
"code": "PLAN_LIMIT_REACHED",
"message": "Склад «Основной»: рабочих мест 3 из 3. Ещё место — 5 000 ₽ в месяц. Добавить места — «Настройки → Тариф и оплата».",
"details": { "warehouseId": "8b1e…", "used": 3, "max": 3 },
"requestId": "0f1c…"
}
}| Код | HTTP | Когда |
|---|---|---|
| VALIDATION_FAILED | 400 | Тело или параметры не прошли схему; код из письма не подошёл или устарел |
| UNAUTHORIZED | 401 | Нет токена или ключа; сеанс завершён — в том числе у сотрудника, снятого с работы; устройство отключено от склада |
| PLAN_LIMIT_REACHED | 402 | Все рабочие места склада заняты |
| FORBIDDEN | 403 | Роли не хватает прав; склад сотруднику не открыт |
| NOT_FOUND | 404 | Нет такой записи или адреса |
| CONFLICT | 409 | Данные изменились; запись уже есть; операция уже отменена |
| TENANT_READONLY | 409 | Счёт не оплачен, организация работает только на чтение: пишущий запрос не проходит ни у человека в панели, ни у ключа интеграции |
| PROTOCOL_VERSION_UNSUPPORTED | 426 | Приложение устройства устарело — обновите его |
| RATE_LIMITED | 429 | Слишком много запросов |
| INTERNAL | 500 | Сбой на сервере; подробности — у поддержки по requestId |
Права
Права поштучные: у каждого действия своё право — «видеть документы», «вести документы», «печатать этикетки», — и маршрут проверяет именно его. Набор прав задаёт роль сотрудника: кладовщик, старший смены, менеджер, начальник склада. Роль выдаётся организацией, а не запрашивается токеном. Ключ интеграции прав не наследует: он либо только читает, либо ещё и ставит заказы.
Постраничность
Постранично отдаются журналы — событий склада и обменов: параметры limit (не больше 200; без него журнал событий отдаёт 50 записей, журнал обменов — 200) и offset. Ответ — { items }, у журнала обменов ещё errors: сколько обменов с ошибкой за выбранный период. Общего числа записей в ответе нет: следующая страница есть, пока пришла полная.
У остальных списков страниц нет. Длинные обрезаются: документы склада — 300 записей, номенклатура — 100, а с limit до 500; нужное в них находят отбором и поиском, а не листанием. Короткие — те, что ограничены складом, периодом или документом, — приходят целиком.
Своя интеграция ничего не обрезает. Остатки склада приходят целиком. Номенклатура (GET /integration/items) без параметров — тоже вся, одним ответом; с limit (до 5000) — страница по артикулу и next. Передайте next в after, чтобы получить следующую; next пустой — номенклатура кончилась. Курсор непрозрачный: его не составляют руками, а берут из прошлого ответа.
Идемпотентность
Операция терминала несёт opId, сгенерированный на устройстве — в том числе когда устройство работало без связи. Повторная отправка того же opId — не второе списание, а пустая операция: это гарантирует сервер.
Заказ своей программы повторяется безопасно по её номеру: externalId в POST /integration/orders обязателен. Заказ с тем же номером второй раз не заводится — ответ 200 и номер уже заведённого.
Остальные создающие запросы принимают заголовок Idempotency-Key — строку от 8 до 128 знаков, своя на каждое действие. Запрос, повторённый с тем же ключом в течение суток, не выполняется второй раз: ответ — тот же, что на первый, с заголовком Idempotent-Replayed: true. Пока первый ещё выполняется, повтор получает 409.
События смены
Изменения на складе приходят по вебсокету на том же адресе: панель подключается сеансом человека, устройство — своим токеном. Событие сообщает, что на складе что-то изменилось; что перечитать, решает клиент. Без сокета экраны опрашивают сервер.
Ограничение частоты
Публичные адреса — регистрация, заявка, отметка захода — ограничены по частоте с одного IP-адреса. Сверх предела сервер отвечает 429 RATE_LIMITED.