«Оплатите по QR-коду» — слышу на кассе каждый день. А как это устроено изнутри?

Когда впервые описывал интеграцию с НСПК, думал: генерируем код, показываем, деньги пришли — что тут сложного. Оказалось: два разных сценария, и касса не получает уведомление от банка, а сама его спрашивает.

Два типа QR-кодов

  • Статический — один на всю точку, на табличке. Раньше покупатель сам вводил сумму (фрод); сейчас QR ведёт на веб-страницу, которая подтягивает сумму от кассы.
  • Динамический — генерируется на каждую транзакцию, сумма уже в коде.

Как касса узнаёт, что оплатили

Кажется, что так: покупатель оплатил → банк шлёт уведомление на кассу (webhook) → «оплачено». Но нет. Касса сама спрашивает банк каждые 2–3 секунды: «оплатили ORD-001?» → нет → пауза → снова → да. Это polling.

Кассе нельзя «позвонить» из интернета — она за роутером или на 4G, без постоянного адреса. Зато сама может позвонить в банк — это работает откуда угодно.

Полный путь динамического QR:

  1. Кассир пробивает товар, 350 ₽ → генерируется уникальный OrderID.
  2. Касса запрашивает у банка создание QR → показывает на экране.
  3. Покупатель сканирует → сумма уже заполнена → подтверждает.
  4. Касса начинает polling: «оплатили OrderID
  5. Банк отвечает «да» → касса печатает чек.
Sequence-диаграмма оплаты по QR: касса создаёт QR в банке, затем опрашивает его каждые 2-3 секунды (polling) до ответа «да», и только потом печатает чек — webhook не используется, потому что касса за роутером

Что забрать аналитику

  • Уточняй тип QR — статический или динамический, у них разный flow.
  • Устройство за NAT/роутером без статического IP → polling, не webhook.
  • Проверяй уникальность OrderID — формат вроде ORD-{TerminalID}-{Timestamp}.
  • Думай о коллизиях: несколько касс и активных чеков на одной точке — при статическом QR это проблема.
  • Крайние случаи: пропал интернет — кто отменяет транзакцию?

Именно эти детали отличают «описал на коленке» от «продумал как надо».