Qut Pay Сайт Кабинет База знаний Инструкции Документация API ҚАЗРУС
ГлавнаяБаза знаний → Справочник

Жизненный цикл счёта

Обновлено: 2026-09-14 · Версия в Markdown

Коротко

Счёт проходит такой путь:

new ──▶ pending ──┬──▶ paid ──┬──▶ refunded
                  │           └──▶ partially_refunded
                  ├──▶ cancelled
                  └──▶ expired

В коде различайте две группы: открытые счета — new и pending; считающиеся оплаченнымиpaid, refunded, partially_refunded. Возвращённый счёт остаётся оплаченным: деньги приходили, потом были возвращены.

Самый важный пограничный случай — поздняя оплата: деньги могут прийти уже по закрытому счёту.

Таблица статусов

СтатусЗначениеОткрытСчитается оплаченным
newСчёт создан, ещё регистрируется в KaspiДаНет
pendingЖдёт оплаты покупателемДаНет
paidОплаченНетДа
cancelledВы его отменилиНетНет
expiredИстёк срок, оплаты не былоНетНет
refundedВозвращён полностьюНетДа
partially_refundedВозвращён частичноНетДа

При фильтрации списка и в отчётах опирайтесь именно на эти две группы, а не перечисляйте каждый статус по отдельности — тогда добавление нового статуса не сломает ваш код.

Переходы

ОткудаКудаЧто произошло
newpendingСчёт зарегистрирован в Kaspi, покупатель может платить
pendingpaidПокупатель оплатил
pendingcancelledВы отправили POST /invoices/{id}/cancel
pendingexpiredПрошёл expiresAt, никто не оплатил
paidrefundedВозвращена вся сумма
paidpartially_refundedВозвращена часть суммы
cancelled / expiredpaidПоздняя оплата. Деньги пришли с опозданием

Обратных переходов нет: оплаченный счёт не станет снова pending, а истёкший сам собой не оживёт.

Какое событие приходит когда

СобытиеКогдаОсобенность тела
invoice.createdПри создании счётаid, externalOrderId, amount
invoice.pendingКогда счёт готов к оплате
invoice.paidКогда покупатель оплатилpaidAt, receiptUrl
invoice.cancelledПри отмене
invoice.expiredПо истечении срока
invoice.failedКогда счёт не прошёл
invoice.refundedПри полном возврате
invoice.partially_refundedПри частичном возврате
invoice.statusОбщее событие на любую смену статусаЕсли нужен один канал на все переходы
invoice.lostЕсли счёт потерян на стороне Kaspi

Список событий выбирается в разделе Интеграции кабинета. Включать все не нужно: чаще всего достаточно invoice.paid и invoice.refunded. Настройка: Настройка вебхуков.

Тайминги

ЧтоСколько
Окно сканирования QRПримерно 3 минуты, точное время в поле expiresAt
Цикл проверки оплатыКаждые 3 секунды
Счёт моложе 3 минутПроверяется на каждом круге
Счёт до 30 минутКаждые 20 секунд
Более старый счётКаждые 90 секунд
От оплаты покупателем до вебхукаОбычно в пределах 5 секунд

Очередь начинается с самых свежих счетов, поэтому только что созданный проверяется первым.

Kaspi не передаёт время оплаты: в данных нет точного момента платежа, поэтому измерить интервал «от подтверждения покупателем до того, как мы узнали» по данным Kaspi невозможно.

Подробнее про сроки: Срок жизни счёта.

Поздняя оплата: главный пограничный случай

По счёту, который уже закрылся как cancelled или expired, деньги могут прийти с опозданием. В этом случае событие invoice.paid придёт позже с пометкой late: true.

Это не ошибка, и случается это редко, но случается. Игнорировать такое событие нельзя — деньги действительно поступили.

Что делать:

  1. Примите событие и верните 200.
  2. Найдите заказ и посмотрите его текущее состояние.
  3. Выберите одно из двух: оказать услугу (товар есть, заказ не аннулирован) или вернуть деньги (API возвратов).
  4. Сообщите покупателю. Молчание — худший вариант.
if (event === 'invoice.paid') {
  const order = await findOrder(invoice.externalOrderId);
  if (invoice.late && order.status === 'closed') {
    await notifyStaff(order, invoice);   // нужно решение человека
  } else {
    await fulfil(order, invoice);
  }
}

Подробнее: Поздняя оплата.

Как читать статус

Каналов два, и они не заменяют друг друга:

КаналКогда использовать
ВебхукОсновной канал. Приходит сам при смене статуса
GET /api/v1/invoices/{id}Когда нужен текущий статус конкретного счёта

В сценариях, где покупатель стоит у устройства и ждёт результата (вендинг, турникет, шлагбаум), используйте оба сразу: первые 30 секунд опрашивайте статус примерно раз в секунду и принимайте то, что придёт раньше. Поэтому обработка обязана быть идемпотентной. Подробнее: Вебхук или опрос статуса.

В ответе GET /api/v1/invoices/{id} приходят также события и возвраты по счёту — удобно как журнал.

Идемпотентная обработка

Одно и то же событие по счёту может прийти несколько раз: оборвалась сеть, вы не успели ответить 200, мы повторили. Поэтому выполняйте обработку ровно один раз по паре (invoice.id, status).

На практике это выглядит так: записываете эту пару в свою базу с уникальным индексом, и если запись не прошла (значит, уже было) — ничего не делаете. Подробнее: Идемпотентность.

Вопросы и ответы

Считается ли refunded оплаченным? Да. Деньги приходили, потом были возвращены. Не исключайте такие счета из группы оплаченных — возврат это отдельный показатель.

Счёт долго висит в pending? Это нормально: покупатель ещё не оплатил. После expiresAt счёт станет expired. Подробнее: Счёт завис в статусе pending.

Я не вижу статуса new, сразу приходит pending. Это обычное дело: счёт регистрируется в Kaspi быстро, поэтому new часто проскакивает незаметно.

Можно ли снова открыть отменённый счёт? Нет. Создайте новый.

А если я пропустил смену статуса? Журнал вебхуков хранится в разделе Интеграции кабинета, а текущий статус счёта всегда можно прочитать запросом GET /api/v1/invoices/{id}.

Связанные статьи

Срок жизни счёта — сколько он действует и что делать дальшеЧем определяется окно сканирования QR-счёта и срок счёта в приложении, как правильно читать поле expiresAt, что делать после статуса expired и почему на уже закрытый счёт деньги могут прийти позже.Поздняя оплата — счёт закрыт, а деньги пришлиНа отменённый или просроченный счёт деньги могут прийти с опозданием. В этом случае событие invoice.paid приходит с меткой late: true. Что делать и как заранее подготовить к этому код.Настройка вебхуковКак добавить адрес вебхука в кабинете, выбрать события и сохранить секрет, какие приходят заголовки и тело, как устроены 11 повторов, как читать журнал, протестировать адрес и что с редиректами.Вебхук или опрос статуса: что когдаВебхук — основной способ узнать об оплате, но гарантия доставки не абсолютна. В сценариях, чувствительных к задержке, нужны оба механизма сразу: как их совместить, с какой частотой опрашивать и почему это не лишняя работа.API возвратов — полный и частичный возвратСправочник по методу POST /invoices/{id}/refund: поля запроса, полный и частичный возврат, ограничение суммы, все коды ошибок, что делать при refund_unknown и какие события приходят после возврата.

Остались вопросы? WhatsApp +77788813333 · kazprose@gmail.com
Написать можно и из кабинета: Поддержка.

Qut Pay — независимый сервис, не аффилирован с АО «Kaspi Bank». Kaspi и Kaspi Pay — товарные знаки их правообладателя.