# Срок жизни счёта — сколько он действует и что делать дальше

> Чем определяется окно сканирования QR-счёта и срок счёта в приложении, как правильно читать поле expiresAt, что делать после статуса expired и почему на уже закрытый счёт деньги могут прийти позже.

## Коротко

У каждого счёта есть свой срок, он приходит в поле `expiresAt`. **Интеграция должна читать именно это поле** — не зашивайте константу: срок задаёт Kaspi, и он может измениться.

Общее правило: **окно сканирования QR-счёта короткое**, а счёт, отправленный в приложение покупателя, живёт заметно дольше. По истечении срока счёт переходит в статус `expired`, «оживить» его нельзя — создаётся новый.

И главное: **на уже закрытый счёт деньги могут прийти с опозданием.** Тогда событие `invoice.paid` приходит с пометкой `late: true`, и ваш обработчик должен быть к этому готов.

## Окно QR-счёта

Когда создаётся QR-счёт, Kaspi отводит на его сканирование короткое время — это сделано намеренно, чтобы картинка QR не жила долго. Конкретное значение **задаёт Kaspi**, а мы возвращаем его в поле `expiresAt`.

Что из этого следует на практике:

- **Не создавайте QR заранее.** Создавайте в момент, когда покупатель уже у кассы или открыл страницу оплаты
- QR на экране **обновляйте до истечения окна**: срок вышел — создайте новый счёт и покажите новый QR
- **Не отправляйте такой счёт в мессенджер или на почту** — пока человек его откроет, срок истечёт. Для этого есть постоянные [ссылки на оплату](/kb/ru/payment-links)
- Если покупатель видит «попробуйте позже», причина обычно именно в этом: [QR показывает «попробуйте позже»](/kb/ru/qr-expired)

## Срок счёта в приложении

Счёт `kind: "phone"` приходит покупателю уведомлением в приложение Kaspi и живёт **значительно дольше** — человек может открыть и оплатить его не сразу.

Точное значение берите там же, в поле `expiresAt`.

| | QR-счёт | Счёт по телефону |
|---|---|---|
| Окно | Короткое, под сканирование | Длинное, покупатель откроет позже |
| Где виден | На экране, на распечатке, на странице оплаты | В приложении Kaspi покупателя |
| Можно создать заранее | Нет | Да |
| Нужен телефон покупателя | Нет | Да |

Полное сравнение: [QR-счёт или счёт по телефону](/kb/ru/qr-vs-phone).

## Как правильно использовать expiresAt

В ответе на создание счёта (`201`) `expiresAt` приходит временем в формате ISO. Правильный порядок работы:

1. Возьмите `expiresAt` из ответа и сохраните у себя.
2. Обратный отсчёт на странице стройте **по этому значению**.
3. Когда время вышло, покажите кнопку «Срок QR истёк, создать новый».
4. По нажатию создайте **новый счёт** — старый не переиспользуется.

Не зашивайте в код никакую константу срока: срок на стороне провайдера может измениться, и ваш таймер начнёт врать.

## Статус expired

Просроченный счёт переходит в `expired`, и приходит событие `invoice.expired`. Это **нормальное завершение**, а не ошибка: покупатель просто не оплатил.

`expired` — финальный статус. Такой счёт:

- ❌ нельзя открыть заново;
- ❌ нельзя продлить;
- ❌ показывать его QR повторно бессмысленно;
- ✅ вместо него создаётся **новый счёт**, тот же `externalOrderId` можно передать снова.

При этом счёт никуда не исчезает: он остаётся в списке, попадает в отчёты, история сохраняется. [Жизненный цикл счёта](/kb/ru/invoice-lifecycle).

Если счёт непривычно долго висит в `pending` — это отдельный случай: [Счёт завис в статусе pending](/kb/ru/invoice-stuck-pending).

## Поздняя оплата: деньги на закрытый счёт

Самая важная часть. На просроченный (`expired`) или отменённый (`cancelled`) счёт деньги **всё ещё могут прийти** — покупатель подтвердил оплату на последних секундах, а информация дошла до нас позже.

В этом случае:

- счёт переходит в `paid`;
- вам приходит событие `invoice.paid` **с пометкой `late: true`**;
- это настоящие деньги, они зачислены на ваш счёт в Kaspi.

Что делать:

1. Обработчик вебхука должен **принимать** `invoice.paid` после `expired` или `cancelled`. Не отбрасывайте его по логике «счёт закрыт, игнорирую».
2. Либо окажите услугу, либо **верните деньги** — одно из двух.
3. Не предлагайте покупателю оплатить повторно: деньги уже пришли один раз.
4. Сделайте обработку идемпотентной по паре «идентификатор счёта + статус»: [Идемпотентность](/kb/ru/idempotency).

Полный разбор сценария: [Поздняя оплата](/kb/ru/late-payment).

Поэтому не считайте, что «окно закрылось — больше ничего не произойдёт»: какое-то время после закрытия статус счёта ещё может измениться. В системах, где товар выдаётся сразу, этот случай стоит продумать отдельно.

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

**Можно ли продлить срок?** Нет. Окно задаёт Kaspi, мы на него не влияем. Если покупателю нужно время — отправьте счёт в приложение.

**Если я отменю счёт сам, деньги могут прийти?** Да, на `cancelled` поздняя оплата тоже возможна — раздел выше действует полностью.

**Просроченные счета считаются в лимите?** Месячный лимит считается по **созданным** счетам, а не по оплаченным. Поэтому не создавайте лишних: [Тарифы и лимиты](/kb/ru/tariff-limits).

**Как это работает в песочнице?** В песочнице статусы вы задаёте сами, включая `expired`: [Симуляция оплаты в песочнице](/kb/ru/sandbox-simulate).

**Можете назвать число минут для QR?** Называть его константой неправильно — Kaspi может его изменить. Всегда читайте фактическое значение из `expiresAt`.
