M cenaly.ru
🔌 Кассовый сервер: чеки по API

🛟 Ошибки, диагностика и надёжность

Разбор кодов ошибок, поведение при офлайне кассового ПК, три рубежа защиты от двойного чека и чек-лист перед запуском в бой

Документация

Ошибки, диагностика и надёжность

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


1. Где какая ошибка появляется#

Ошибки приходят в двух местах, и это разные классы проблем:

Где Класс Пример
В ответе на регистрацию (HTTP 4xx) Запрос не принят: авторизация, схема чека, несовпадение ИНН, дубль 10, 11, 12, 32, 33
В результате документа (report, документ уже принят) Не удалось пробить: касса офлайн, отказ кассы 2001, 2002, type: "timeout" с кодом 1, ошибки драйвера

Первый класс исправляется в коде интеграции. Второй — на стороне кассы и оборудования.

Коды 2001, 2002 и 2003 сервис выдаёт: 2001 — за 300 с чеку так и не досталась касса (все офлайн либо заняты), 2002 — касса не умеет такой чек, 2003 — ИНН чека не совпадает с ИНН группы (отвечаем сразу на регистрации, HTTP 400). Разбор каждого — ниже.


2. Ошибки запроса#

10 · 11 · 12 — авторизация#

Код Причина Решение
10 Токен не передан Заголовок Token: <токен> или ?token=
11 Токен истёк (живёт 24 часа) или неизвестен Получить новый через getToken
12 Неверный логин или пароль Проверить реквизиты группы
20 Токен выдан для другой группы Сверить group_code в пути
21 Группа не работает по этой версии протокола Проверить v5 / v4 в пути

Практика: кэшируйте токен на 23 часа и обновляйте по ошибке 11, а не по расписанию.

32 — валидация чека#

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

{ "error": { "code": 32, "type": "system",
  "text": "items[0].measure обязателен (v5, тег 2108)" } }

Типовые причины:

Текст ошибки Что не так
receipt.client: обязателен минимум один из email|phone Электронный чек некуда отправить
receipt.company.inn: ожидается 10 или 12 цифр ИНН с пробелами, дефисами или не тот
items[N].payment_object обязателен (v5) Не передан признак предмета расчёта
items[N].measure обязателен (v5, тег 2108) Единица измерения строкой вместо кода
items[N].measurement_unit не поддерживается в v5 Смешаны v4 и v5 в одном чеке
receipt.total (…) не равен сумме позиций (…) Скидка вычтена из total, но не из позиций
сумма оплат (…) не равна receipt.total (…) Округление в оплате
items[N].supplier_info с валидным inn обязателен при agent_info Агентская позиция без поставщика
receipt.company.inn (…) не совпадает с ИНН группы (…) ИНН чека не тот, на который зарегистрирован ФН касс группы

Сверьте состав чека со справочником реквизитов — там перечислено, что обязательно в v5, а что в v4.

Последняя строка — про ИНН — отрабатывается до постановки в очередь: чек с чужим ИНН отклоняется сразу (HTTP 400, код 32), документ не создаётся и external_id не расходуется. Сверьте ИНН с карточкой регистрации ККТ и с реквизитами, указанными при создании кассового сервера.

33 — дубль external_id#

Это не ошибка интеграции, а штатный ответ на повтор. В теле ответа приходит uuid первого документа:

{ "uuid": "47b30214-…", "status": "wait",
  "error": { "code": 33, "text": "документ с таким external_id уже принят в этой группе" } }

Правильная реакция: взять uuid и запросить по нему report. Ошибкой это становится только если вы случайно переиспользовали external_id для другого расчёта.

30 · 34 — работа с report#

  • 30 — неизвестный uuid: опечатка, чужая группа или документ старше 60 дней (архив).
  • 34 — документ ещё не обработан. Приходит с HTTP 200 и status: wait; просто продолжайте ждать.

429 — превышен лимит#

Регистрация ограничена 10 запросами в секунду на группу, поллинг — 1 запрос в секунду на каждую кассу группы. Повторите с задержкой; для поллинга разумный интервал — 2–3 секунды, а лучше подписаться на callback_url.


3. Ошибки в report: документ принят, но не пробит#

Код 2001 (type: "timeout") — 300 секунд ожидания кассы#

Документ пролежал в очереди 5 минут и не дождался онлайн-кассы группы: кассовый ПК выключен, нет интернета, мост не запущен — либо все кассы группы заняты другими документами дольше отведённого времени. Текст ошибки: «очередь: за 300 с в группе не нашлось свободной кассы (все кассы офлайн либо заняты)».

Отдельно от него стоит код 1 с тем же type: "timeout": касса чек ВЗЯЛА, но за 300 с не отчиталась о результате (зависла, оборвалась связь в момент печати). Здесь, в отличие от 2001, документ мог уйти в ФН — прежде чем повторять расчёт, сверьте последний чек на самой кассе.

Что делать:

  1. Проверить, что кассовый ПК включён и мост запущен (страница статуса моста на самом ПК); связь каждой кассы видна и в админке — раздел «API кассы»;
  2. Проверить связь ПК с интернетом;
  3. Если ПК и мост в порядке, а таймауты повторяются на пиках — добавить в группу вторую кассу, в том числе резервную: очередь обслуживает документы по времени поступления;
  4. Повторить расчёт новым external_id — старый документ уже финализирован как fail.

Ошибки драйвера кассы#

Всё, что касса ответила сама, приходит её текстом: «нет бумаги», «касса заблокирована», «открыт незавершённый чек», «ФН переполнен», «смена превысила 24 часа — снимите Z-отчёт» (см. Смена больше 24 часов). Разбор частых кодов — Ошибки АТОЛ и Ошибки ШТРИХ-М.

Сюда же попадает и несовместимость чека с моделью кассы — такой отказ приходит с кодом 2002 и текстом драйвера:

  • ККТ не умеет электронный чек без печати — для интернет-расчётов это обязательное свойство (сегодня уверенно поддерживают кассы АТОЛ);
  • в чеке есть маркировка, а касса без поддержки ФФД 1.2;
  • расширенные реквизиты покупателя или отраслевые реквизиты, которых модель не знает.

Что делать: проверить модель кассы и версию ФФД; при необходимости завести в группу подходящий аппарат. Отбор кассы «по способностям» очередь не делает — документ уходит на любую онлайн-кассу группы, поэтому в одной группе держите однотипные по возможностям аппараты.


4. Защита от двойного чека#

Двойной налоговый документ на одну оплату — худшая из возможных ошибок фискальной интеграции: его придётся сторнировать чеком коррекции и объясняться с ФНС. В сервисе против этого работают три рубежа:

  1. external_id на приёме. Повтор в пределах группы возвращает прежний uuid (ошибка 33) и никогда не создаёт второй документ.
  2. Ключ операции до самой кассы. Мост получает ключ, построенный из группы и external_id, и ведёт журнал операций на диске. Повтор возвращает первый результат — даже если кассовый ПК успел перезагрузиться.
  3. Честный отказ при неизвестном исходе. Если связь оборвалась ровно в момент закрытия чека (документ мог уйти в ФН, а мог и нет), повтор этой операции отклоняется с требованием сверить последний документ на кассе. Вслепую второй чек не пробивается.

Что требуется от вашей стороны:

  • один расчёт — один external_id, стабильный при ретраях (например order-10421, а не случайный UUID на каждую попытку);
  • никогда не менять external_id «чтобы прошло»: если документ не пробился, сначала выясните почему;
  • обработчик callback — идемпотентный: одно и то же уведомление может прийти повторно.

5. Что делать, если касса офлайн#

Кассовый ПК выключен или без интернета — чек не пробьётся: касса физически ваша, и облако не может её заменить. Поведение сервиса:

  • документ ждёт в очереди до 300 секунд;
  • если касса появилась в это время — чек пробивается штатно;
  • если нет — документ переходит в fail с типом timeout.

Рекомендации для магазинов с круглосуточным приёмом заказов:

  1. Держать кассовый ПК включённым (энергосбережение и «сон» — выключить);
  2. Поставить вторую кассу в группу как резервную;
  3. В своей системе иметь очередь неотправленных чеков и повторять их новым external_id, когда касса вернулась онлайн, — с учётом того, что по закону чек формируется не позднее следующего рабочего дня;
  4. Настроить мониторинг: fail с timeout — это инцидент, о котором должен узнать человек.

6. Чек-лист перед запуском в бой#

  • ККТ зарегистрирована с признаком «расчёты в Интернете», в теге 1187 — адрес сайта;
  • ИНН в receipt.company.inn совпадает с ИНН регистрации ФН;
  • СНО в чеке соответствует вашей реальной системе налогообложения;
  • external_id детерминирован и переживает ретраи;
  • обработан ответ 33 (взять uuid из ответа, не считать это сбоем);
  • реализован и поллинг, и callback_url — второй не заменяет первый;
  • признание оплаты фискализированной — только по status: done;
  • ФД, ФПД, ФН и РН ККТ сохраняются в заказе;
  • fail и timeout попадают в мониторинг, а не только в лог;
  • проверено поведение при выключенном кассовом ПК;
  • для маркированных товаров проверка кода выполняется до отправки чека;
  • проверены ставки НДС на реальной прошивке кассы (особенно 22 % и расчётные).

7. Куда смотреть при разборе инцидента#

Вопрос Где ответ
Что именно мы отправили Ваш лог запроса + external_id
Что ответил сервис report по uuid (хранится не менее 32 суток)
Дошло ли до кассы device_code в report — код кассы, на которую ушёл документ
Что сказала касса Поле error в report; журнал чеков и последняя ошибка — в разделе «API кассы»
Есть ли чек в ФН Номер ФД из payload + личный кабинет ОФД
Был ли повтор Ошибка 33 в ваших логах и совпадающий uuid

Поле error — всегда объект {error_id, code, text, type}, в том числе при отказе драйвера: текст кассы приходит от моста строкой, а сервис заворачивает его в объект и проставляет код (2002 — касса не умеет такой чек, 1 — прочий отказ) и type: "driver". error_id у одного и того же отказа не меняется между поллингами — его можно указывать в обращении в поддержку.

Если чек пробит, а ваша система об этом не узнала (потеряли callback и не поллили), документ всё равно существует: найдите его по external_id через report и досохраните реквизиты — повторно пробивать не нужно.


Дальше: справочник API · реквизиты чека · сценарии магазина.