Перейти к содержимому

Аутентификация

Каждый запрос к /api/payments/v1/, кроме подключения, несёт учётные данные устройства:

Authorization: Bearer sit_pd_<hex>

Устройство регистрирует владелец ресторана в Sitora Biz, а затем вооружает его одноразовым кодом подключения. Код живёт один час и годится для одного погашения. Погашение — единственная анонимная операция на этой поверхности: код и есть секрет, поэтому эндпоинт ограничен по IP, а неизвестные, погашенные и просроченные коды отвечают одинаково — 400 и {"code": "enrollment_invalid"}.

Погашение возвращает учётные данные ровно один раз. Sitora хранит только хеш; эндпоинта, который вернёт ваш ключ ещё раз, не существует.

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

Учётные данные устройства — не учётная запись пользователя. У них нет членства, нет роли и нет прав сотрудника. Они никогда не могут создать заказ, транзакцию или сессию и никогда не появляются как действующий субъект.

Сотрудники, работающие за устройством — кассир на смарт-кассе, — аутентифицируются сами собой, своей обычной сессией Sitora Pro. Один запрос — это всегда ровно один субъект: человеческие действия едут на сессии сотрудника, устройственная поверхность — на учётных данных устройства. Не пытайтесь использовать одно вместо другого.

Учётные данные разрешаются ровно в одно устройство, которое принадлежит ровно одной кассе ровно в одном филиале. Вы никогда не присылаете идентификатор филиала или кассы — Sitora выводит их из ключа. Учётные данные одной кассы не видят работу другой даже внутри одного ресторана.

Scope Выдаётся, когда устройство объявляет Даёт
device:heartbeat всегда Heartbeat и снимок самого себя
device:display qr_dynamic_present или customer_total_display Очередь экрана
intents:read_assigned payment_app_handoff Чтение назначения
intents:report_handoff payment_app_handoff Отчёт об исходе

Поскольку scope выводятся из возможностей, изменить возможности устройства — значит подключить его заново; именно поэтому выпуск кода отзывает старый ключ.

Правомочность выводится заново на каждом запросе

Заголовок раздела «Правомочность выводится заново на каждом запросе»

Авторизация не решается один раз при подключении. Каждый запрос заново проверяет, что платформа не заморожена, устройство активно, его касса активна и филиал активен. Поэтому пауза действует уже на следующем вызове, посреди смены, и никакого кэша пережидать не нужно.

Отказ называет свою причину:

Причина Значение
platform_frozen Приём денег через провайдера заморожен на всей платформе (только экраны)
device_paused / device_retired Владелец приостановил или вывел это устройство
device_not_enrolled Устройство ждёт нового погашения кода подключения
station_retired Касса, которую обслуживает устройство, выведена
filial_inactive Филиал не активен

Сам 403 не машиночитаем: его тело — {"detail": "Device credential refused: station_retired."}, причина внутри предложения. Чтобы ветвиться по причине, читайте её как отдельное поле из собственного снимка устройства:

GET /api/payments/v1/devices/me/

Этот эндпоинт отдаёт тот же снимок, что и heartbeat, — имя устройства, вид, возможности, статус, имя и статус его кассы, настроенную цель передачи — плюс blocked_reason, который несёт код из таблицы выше или пустую строку, когда устройство правомочно. Ему нужен только device:heartbeat, поэтому спросить может любое подключённое устройство.

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