Коротко
В аренде всегда два разных денежных движения: залог (гарантия, чаще всего возвращается) и плата за аренду (не возвращается). Не смешивайте их в одном счёте — делайте два счёта, тогда возврат будет чистым. Если вещь выдаёт автомат или замок, схема одна: клиент сканирует QR → оплачивает → на ваш сервер приходит вебхук invoice.paid → ваш сервер открывает устройство. Номер устройства заранее кладётся в поле metadata.
Кому подходит
Станции пауэрбанков, велосипеды и самокаты, инструмент, строительное оборудование, вечерние платья и костюмы, фототехника, палатки — порядок везде одинаковый.
Схема работы по шагам
Вариант с выдачей автоматом:
| Шаг | Кто | Что происходит |
|---|---|---|
| 1 | Клиент | Сканирует QR на станции приложением Kaspi |
| 2 | Станция или ваш сервер | POST /api/v1/invoices — создаёт счёт, кладёт в metadata слот и номер устройства |
| 3 | Клиент | Подтверждает в Kaspi |
| 4 | Qut Pay | Отправляет событие invoice.paid на ваш адрес |
| 5 | Ваш сервер | Читает номер устройства из metadata и открывает замок |
| 6 | Клиент | Забирает вещь |
В пункте проката с сотрудником вместо шага 5 вещь выдаёт человек — остальное то же самое.
Как брать залог
Делайте два счёта:
| Счёт | Сумма | Описание | Что с ним дальше |
|---|---|---|---|
| Аренда | По сроку | «Велосипед, 2 часа» | Остаётся у вас |
| Залог | Фиксированная | «Велосипед, залог» | Возвращается |
Почему раздельно? Возврат делается по счёту. Если объединить, для возврата залога придётся делать частичный возврат, а учёт запутается.
Залог — это реальные деньги, клиент их действительно платит. Мы не умеем блокировать сумму: у нас нет «замороженных» средств, деньги сразу уходят на ваш счёт Kaspi. Поэтому возврат залога — это настоящая операция возврата, которую делаете вы.
Скажите об этом клиенту заранее: «залог возвращаем, обычно в тот же день».
Возврат залога
Когда вещь принята и проверена:
POST https://api.qut.kz/api/v1/invoices/{id счёта залога}/refund
{ "reason": "вещь возвращена в целости" }
Без amount возвращается вся сумма.
Частичный возврат
Если вещь повреждена или сдана позже срока, часть залога вы удерживаете:
POST https://api.qut.kz/api/v1/invoices/{id}/refund
{ "amount": 7000, "reason": "просрочка 1 час" }
Здесь amount — сумма, которую вы возвращаете, а не удерживаете. Если из залога 10 000 ₸ нужно удержать 3 000 ₸, пишете 7000. Счёт переходит в partially_refunded.
Бывает, что ответ по возврату остаётся неопределённым (refund_unknown) — не повторяйте сразу, сначала прочитайте состояние счёта. Подробнее: API возвратов.
Периодическая оплата
Для длинной аренды (оборудование на месяц, помесячный прокат) есть два пути:
1. Счёт вручную на каждый период. Из кабинета или через API. Перед концом срока отправляете клиенту ссылку. Самый гибкий вариант: сумма может меняться от месяца к месяцу.
2. Подписка. Счёт выставляется по расписанию сам, интервалы day, week, month. Но важно: деньги со счёта клиента сами не уходят, каждый счёт он подтверждает в Kaspi вручную. Подробнее: Бизнес по подписке.
Для посуточной или почасовой аренды (самокаты, велосипеды) подписка не подходит — там правильнее отдельный счёт на каждую поездку.
Metadata: пишем номер устройства
Это самая важная техническая деталь в аренде. При создании счёта:
{
"amount": 500,
"kind": "qr",
"description": "Пауэрбанк, 2 часа",
"externalOrderId": "rent-90412",
"metadata": {
"station": "ALM-014",
"slot": 7,
"deviceId": "PB-33921",
"type": "rent",
"hours": 2
}
}
metadata — произвольный JSON. Он возвращается в вебхуке, поэтому при получении invoice.paid не нужно искать в базе, какой слот какой станции открыть — всё лежит в самом событии.
externalOrderId — ваш номер аренды, он тоже приходит обратно. Используйте оба поля: Metadata и номер заказа.
В счёте залога поставьте "type": "deposit" — тогда обработчик вебхуков не перепутает его с арендой.
Что важно на стороне вебхука
- Обработка должна быть идемпотентной. Одно событие может прийти несколько раз. Проверяйте по паре
(invoice.id, status): если замок по этому счёту уже открывался, второй раз не открывайте. - Проверяйте подпись.
X-Webhook-Signature— этоHMAC-SHA256(secret, timestamp + "." + rawBody). Считайте по нетронутому телу запроса, до разбора JSON. - Отвечайте быстро. На ответ не из 2xx доставка повторится 11 раз. Если открытие замка долгое, положите событие в очередь и сразу верните 200.
- Адрес должен быть открыт. В бою — только
httpsи настоящий домен, без авторизации.
Настройка: Настройка вебхуков.
На что обратить внимание
- Окно сканирования QR — около трёх минут. Если клиент у станции задумался, счёт станет
expired. Держите на экране кнопку «Обновить QR». - Поздняя оплата. Деньги могут прийти уже после того, как счёт стал
expired— событиеinvoice.paidпридёт с признакомlate: true. Клиент в этот момент, скорее всего, стоит у станции: выдайте вещь или сразу верните деньги. Заложите этот случай в логику. - Станция без связи. Если пропал интернет, счёт не создастся. Продумайте поведение автомата на этот случай.
- Не завышайте залог. Слишком большой залог отпугивает клиента и увеличивает объём возвратов.
- Деньги приходят напрямую на ваш счёт Kaspi, у нас не задерживаются.
Вопросы и ответы
Можно заморозить залог и потом «разморозить»? Нет, такого механизма нет. Залог — полноценный платёж, для возврата делается операция возврата.
Есть ли срок на возврат? Да, ограничение есть. Не держите залог месяцами при длинной аренде — сроки и ошибки: API возвратов.
У автомата нет экрана, можно наклеить статичный QR? Постоянную ссылку сделать можно, но тогда счёт не будет привязан к конкретному устройству. Схема получится как у парковок: Парковки и шлагбаумы и Оплата в вендинговом автомате.
А если клиент не вернёт вещь? Залог остаётся у вас на счёте Kaspi, делать ничего не нужно. Остальное — ваш вопрос с клиентом.
У меня несколько станций, хочу раздельный учёт. Заведите отдельный API-ключ на станцию или фильтруйте по metadata.station: Раздельная отчётность по точкам.