Коротко
На парковке схема такая: водитель подъезжает к выезду → вводит номер билета или его госномер считывает камера → ваш сервер считает сумму по времени стоянки и создаёт счёт в Qut Pay → на экране появляется QR → водитель сканирует и подтверждает в Kaspi → к вам приходит вебхук → сервер через IP-реле открывает шлагбаум. QR создаётся заново на каждый выезд: окно сканирования около трёх минут. Водитель платит, не выходя из машины.
Как это работает
| Шаг | Кто | Что делает |
|---|---|---|
| 1 | Водитель | Подъезжает к выезду, вводит номер билета |
| 2 | Контроллер парковки | Запрос на сервер: номер билета, время въезда, госномер |
| 3 | Ваш сервер | Считает сумму и делает POST /api/v1/invoices |
| 4 | Экран | Показывает QR и таймер |
| 5 | Водитель | Сканирует в Kaspi и подтверждает |
| 6 | Qut Pay | Шлёт на сервер invoice.paid |
| 7 | Ваш сервер | Отправляет команду на IP-реле |
| 8 | Шлагбаум | Открывается, событие пишется в журнал |
После подтверждения вебхук обычно приходит в пределах пяти секунд. На выезде даже это долго: сзади стоит очередь. Поэтому обязательно прочитайте раздел про задержку ниже.
Какой метод API используется
Основной — POST /api/v1/invoices с kind: "qr":
POST https://api.qut.kz/api/v1/invoices
X-API-Key: qp_live_…
Idempotency-Key: park-exit-4471
{
"amount": 600,
"kind": "qr",
"description": "Парковка: билет 4471, 2 ч 15 мин",
"externalOrderId": "park-4471",
"metadata": {
"ticket": "4471",
"plate": "123ABC02",
"gate": "exit-2",
"entered_at": "2026-09-14T09:12:00Z"
}
}
Нужны id, qrImageUrl, expiresAt. Остальное: GET /api/v1/invoices/{id} — статус, POST /api/v1/invoices/{id}/cancel — водитель уехал не заплатив, POST /api/v1/invoices/{id}/refund — шлагбаум не открылся.
Если у вас есть абонементы, ежемесячную оплату можно поставить на расписание подписками. Но помните: подписка выставляет счёт по расписанию, а подтверждает оплату клиент сам каждый раз.
Кладите госномер в metadata
В metadata обязательно положите: номер билета, госномер машины, какой шлагбаум, время въезда. Когда придёт вебхук, вы сразу знаете, какой шлагбаум открывать.
Это же нужно и для разбора споров: на реплику «я оплатил, а он не открылся» вы находите счёт по госномеру и показываете всю последовательность событий. В externalOrderId кладите номер билета — так проще искать.
Если парковок несколько, заведите на каждую свой API-ключ: отчётность разделится по точкам.
Динамический и печатный QR
Динамический QR (основной путь). На экране на каждый выезд показывается новый счёт. Сумма посчитана именно для этой машины, оплата привязана к конкретному билету, шлагбаум открывается автоматически. Используйте этот путь.
Печатный QR (запасной). У выезда можно повесить постоянный бумажный код, но это не должен быть QR счёта: у счёта окно около трёх минут, и назавтра он перестанет работать. Для постоянного кода используйте ссылку на оплату qut.kz/p/<slug>, есть и вариант с открытой суммой.
У печатного кода есть слабое место: оплата не привязана к конкретному билету, поэтому шлагбаум сам не откроется. Его открывает охранник вручную или оператор, увидев оплату в кабинете. Это запасной вариант — на случай отказа автоматики или для маленькой парковки.
| Динамический QR | Печатная ссылка на оплату | |
|---|---|---|
| Сумма | Посчитана точно | Вводит клиент или фиксированная |
| Привязка к билету | Есть | Нет |
| Шлагбаум открывается сам | Да | Нет, вручную |
| Срок жизни | Около 3 минут | Не истекает |
| Где уместно | Основной путь | Запасной, небольшая парковка |
Что нужно со стороны железа
- Экран и клавиатура на выезде — показать QR и ввести номер билета.
- Сервер в облаке — считает сумму, создаёт счета, принимает вебхуки, шлёт команду на шлагбаум. API-ключ лежит только здесь.
- IP-реле или контроллер — подключается ко входу «открыть» у шлагбаума. Сервер шлёт команду, реле замыкает контакт.
- Связь — интернет на парковке обязателен. Стоит предусмотреть резервный GSM-канал: без сети шлагбаум работать не будет.
Не выставляйте реле напрямую в интернет. Оно должно принимать команды только от вашего сервера. И не кладите API-ключ в реле или локальный контроллер.
Задержка критична: вебхук и опрос вместе
На выезде даже несколько секунд — это долго. Поэтому держите два канала сразу:
- Вебхук — основной. Пришёл
invoice.paid— шлагбаум открывается. - Опрос статуса — страховка. После создания счёта контроллер каждые 2-3 секунды запрашивает
GET /api/v1/invoices/{id}. Кто первым увидитpaid, тот и открывает — считайте это одним событием и не открывайте дважды.
Поллер на нашей стороне ходит каждые три секунды, а счета моложе трёх минут проверяются на каждом круге — то есть статус свежего счёта обновляется чаще всего. Про скорость в целом: Оплата подтверждается медленно.
Если вебхук не приходит вовсе, причину видно в журнале доставок: Вебхук не приходит.
На что обратить внимание
- Идемпотентность. Если водитель нажмёт «QR» несколько раз, новых счетов быть не должно. Передавайте номер билета в
Idempotency-Key. - Обработчик вебхука должен быть идемпотентным. Пара
(invoice.id, status)обрабатывается один раз, иначе шлагбаум откроется дважды и следом проедет чужая машина. - Не открылся шлагбаум — возврат. Деньги пришли, а реле не сработало (пропал интернет, отказало железо) — делайте
refund. Это самый частый спор на парковке. - Поздняя оплата. Если деньги придут на истёкший счёт, событие придёт с признаком
late: true. Водителя уже нет — возвращайте деньги. - Оставьте охраннику ручное открытие. При обрыве связи парковка не должна вставать.
- Пишите в журнал каждое событие: счёт создан, оплачен, команда на реле ушла, шлагбаум открылся. В спорной ситуации помогает только он.
- Сначала песочница. Прогоните всю цепочку ключом
qp_test_…: счёт →simulate→ вебхук → команда на реле: Чем песочница отличается от боевого режима.
Вопросы и ответы
Можно один раз напечатать QR и повесить на выезде? QR счёта — нет, у него окно около трёх минут. Для постоянного кода подойдёт ссылка на оплату, но тогда шлагбаум автоматически не откроется.
У нас нет билетов, госномер читает камера. Подойдёт? Да. Порядок расчёта суммы и создания счёта тот же, просто в metadata вместо билета кладёте госномер.
Если я продаю абонементы, деньги будут списываться сами? Нет. Подписка выставляет счёт по расписанию, а оплату клиент каждый раз подтверждает в Kaspi сам.
Водитель не успел оплатить, и время QR вышло. Создаёте новый счёт — на экране должна быть кнопка «Показать заново». Старый счёт останется expired, деньги по нему не спишутся.
Что будет, если пропадёт интернет? Не работают ни создание счёта, ни вебхуки. Поэтому заранее предусмотрите резервный GSM-канал и ручное открытие охранником.