Коротко
pending — это состояние ожидания, а не ошибка. Оно означает «счёт выставлен, покупатель пока не подтвердил оплату». В этом статусе счёт живёт до конца своего срока, а затем сам переходит в expired. Делать ничего не нужно: мы постоянно проверяем счёт в фоне, и в момент оплаты статус меняется на paid, а вам уходит вебхук. Волноваться стоит только в одном случае — если в pending застревают все ваши счета подряд.
Статусы счёта
new → pending → paid
→ cancelled
→ expired
Оплаченный счёт позже может стать refunded или partially_refunded.
| Статус | Что значит | Открыт |
|---|---|---|
new | Счёт создан, ещё не показан покупателю | Да |
pending | Показан покупателю, ждёт подтверждения | Да |
paid | Покупатель оплатил, деньги на вашем счёте Kaspi | Нет |
cancelled | Вы отменили счёт | Нет |
expired | Срок истёк, оплаты не было | Нет |
new и pending считаются открытыми — они ещё могут быть оплачены. paid, refunded и partially_refunded считаются оплаченными.
Сколько он живёт
Зависит от вида счёта, и срок задаёт Kaspi — продлить его со своей стороны мы не можем.
| Вид | Что это | Срок |
|---|---|---|
qr | QR-код и ссылка на оплату | Окно сканирования короткое, около трёх минут |
phone | Push в приложение Kaspi покупателя | Дольше: покупатель может открыть уведомление позже |
Не зашивайте конкретное число в код. В ответе на создание счёта приходит поле expiresAt — берите срок оттуда. Если Kaspi изменит окно, ваш код подстроится сам.
Когда окно QR истекает, покупатель при сканировании видит сообщение «попробуйте позже». Об этом отдельная статья: QR показывает «попробуйте позже».
Как мы это проверяем
Kaspi не сообщает нам об оплате сам — мы опрашиваем статусы счетов. Опрос идёт каждые три секунды, а каждый конкретный счёт проверяется с частотой, зависящей от его возраста:
| Возраст счёта | Частота проверки |
|---|---|
| До 3 минут | В каждом цикле |
| До 30 минут | Раз в 20 секунд |
| Старше | Раз в 90 секунд |
Очередь начинается с самых свежих счетов — то есть оплата покупателя, который стоит у кассы прямо сейчас, проверяется в первую очередь. На практике вебхук после оплаты приходит обычно в пределах пяти секунд.
Важная оговорка: Kaspi не передаёт точное время оплаты. Поэтому измерить по данным Kaspi, сколько прошло от подтверждения покупателем до момента, когда мы узнали об оплате, невозможно.
Когда действительно стоит волноваться
Сам по себе pending — не проблема. Проблема — вот это:
- Все счета остаются в pending и ни один не становится paid. Скорее всего включён тестовый режим: Оплата не приходит покупателю.
- Покупатель говорит, что оплатил, а счёт всё ещё pending. Подождите минуту. Если не изменился, уточните операцию в приложении Kaspi: оплата могла уйти по совсем другому счёту.
- Счёт стал paid, но вебхук до вас не дошёл. Это отдельная проблема: Вебхук не приходит.
- Счета в pending копятся сотнями. Возможно, ваш код выставляет лишние счета, которые никто не собирается оплачивать.
Чего делать не надо
- Не считайте pending оплатой. Выдавайте товар или услугу только после статуса
paid. - Не создавайте одному покупателю счёт за счётом. Пока старый в pending, новый может быть оплачен вдобавок к нему — человек заплатит дважды.
- Не опрашивайте статус слишком часто. Мы и так проверяем его сами, а частый опрос упрётся в ограничение частоты запросов.
- Не пытайтесь вернуть деньги по pending-счёту. Он ещё не оплачен, возвращать нечего.
Поздняя оплата
Бывает, что деньги приходят по счёту, который уже стал expired или cancelled. Тогда событие invoice.paid приходит вам позже и с пометкой late: true.
Это настоящая оплата — деньги на вашем счёте Kaspi. Дальше выбор из двух: оказать услугу или вернуть деньги. Правильнее всего сразу научить обработчик замечать признак late и складывать такие счета в отдельный список для разбора.
Вопросы и ответы
Можно ли отменить счёт в pending? Да, через POST /api/v1/invoices/{id}/cancel. Если покупатель ещё не оплатил, счёт закроется.
Можно ли оживить expired-счёт? Нет, создаётся новый.
Считаются ли pending-счета в лимит тарифа? Месячный лимит считается по количеству созданных счетов, а не оплаченных.
Покупатель отсканировал QR, но не заплатил — статус изменится? Нет, статус становится paid только после реального подтверждения. Само сканирование оплатой не является.
Как вывести счёт из pending в песочнице? Через POST /api/v1/invoices/{id}/simulate вы сами задаёте нужный статус. Этот метод работает только в песочнице.