# Подписка не выставляет счета

> Если подписка не создаёт счета по расписанию, проверить нужно шесть вещей: статус, время следующего запуска, лестницу ретраев, политику пропуска, кассира и лимит тарифа. Где смотреть lastRunStatus и lastError.

## Коротко

Подписка — это **автоматическое выставление счетов по расписанию**. Деньги со счёта покупателя сами не уходят: каждую оплату он подтверждает в Kaspi сам. Поэтому «подписка не работает» означает две разные вещи — счёт вообще не создался или счёт создался, но покупатель его не оплатил. Начните с полей `lastRunStatus` и `lastError`: ответ обычно именно там.

## Симптом → причина → решение

| Симптом | Причина | Решение |
|---|---|---|
| Счёт вообще не появился | Подписка в статусе `paused` или `closed` | Проверьте статус, при необходимости сделайте `resume` |
| Время пришло, счёта нет | Следующий запуск назначен на другое время | Посмотрите время следующего запуска |
| Счёт появился с опозданием | Идёт лестница ретраев | Проверьте значения `retryDelaysMin` |
| Один запуск пропущен полностью | `misfirePolicy: skip` | Поставьте политику `run_once` |
| В `lastError` ошибка привязки Kaspi | Сессия кассира оборвалась | Переподключите: [Кассир Kaspi не подключается](/kb/ru/cashier-not-connecting) |
| В `lastError` лимит тарифа | Кончился месячный лимит | [Достигнут лимит](/kb/ru/tariff-limit-hit) |
| Счета выставляются, денег нет | Покупатели не оплачивают | Это не ошибка, оплата на стороне покупателя |

## Что читать в первую очередь

У самой подписки есть три поля для диагностики:

| Поле | Что показывает |
|---|---|
| `lastRunStatus` | Результат последнего запуска |
| `lastError` | Если неудачно — конкретный код ошибки |
| `failedRuns` | Сколько запусков подряд оказались неудачными |

Код в `lastError` объясняет всё остальное. Например `kaspi_session_expired` — проблема в кассире, `tariff_limit_reached` — в тарифе, `invalid_phone` — в данных покупателя.

## Шесть проверок

### 1. Статус подписки

Статусов три: `active`, `paused`, `closed`.

- **`paused`** — приостановлена. Запуски не идут. Включается через `POST /subscriptions/{id}/resume`.
- **`closed`** — завершена или остановлена. Её нельзя включить обратно, нужно создать новую (иначе придёт `subscription_closed`).

Подписка может стать `closed` сама, если исчерпано заданное максимальное число запусков.

### 2. Время следующего запуска

В расписании два параметра: интервал (`day`, `week`, `month`) и кратность `every`. Например `month` + `every: 2` — раз в два месяца.

Частое недоразумение: ожидание, что счёт появится сразу в момент создания подписки. Расписание отсчитывается от времени первого запуска, а он может быть не сегодня. Время следующего запуска смотрите в карточке подписки или в ответе `GET /subscriptions/{id}`.

### 3. Лестница ретраев

Если запуск оказался неудачным, подписка не останавливается сразу — она пробует ещё раз по лестнице ретраев. По умолчанию `retryDelaysMin: [15, 60, 360]` минут: через 15 минут, потом через час, потом через шесть часов. Максимум 5 значений.

Пока лестница не пройдена, со стороны кажется, что счёт просто не выставляется. В это время `lastError` уже заполнен — причину читайте оттуда.

Когда лестница закончилась, **этот запуск отбрасывается, но расписание продолжается**: следующий плановый запуск пойдёт в своё время. Счётчик `failedRuns` при этом растёт.

### 4. Политика пропуска

Если момент запуска по какой-то причине был пропущен, что делать дальше, решает `misfirePolicy`:

| Значение | Что происходит |
|---|---|
| `run_once` (по умолчанию) | Пропущенный запуск выполняется один раз позже |
| `skip` | Пропущенный запуск не выполняется вовсе |

`misfireAfterMin` — через сколько минут запуск считается пропущенным, по умолчанию 1440 (сутки).

Если у вас стоит `skip`, пропущенный счёт не появится вообще — это не сбой, так настроено.

Чтобы отправить пропущенный запуск вручную: `POST /subscriptions/{id}/resume` с телом `{ "catchUp": true }`.

### 5. Активен ли кассир

Подписка **запоминает, через какого кассира она создана**. Если привязка Kaspi у этого кассира оборвалась, запуск не сможет создать счёт.

Сценарий встречается часто: кто-то заходит с номера кассира в приложение Kaspi Pay, сессия обрывается, а подписка молча пишет ошибку в `lastError`. Проверка: кабинет → раздел **Kaspi**, активна ли привязка. Подробнее: [Кассир Kaspi не подключается](/kb/ru/cashier-not-connecting).

### 6. Лимит тарифа

Когда месячный лимит исчерпан, подписка тоже не может создать новый счёт — он считается как обычный. В `lastError` будет `tariff_limit_reached`.

Если подписок много, заложите их месячный объём заранее при выборе тарифа: [Какой тариф выбрать](/kb/ru/tariff-choose).

## Что чаще всего понимают неправильно

Подписка не забирает деньги со счёта покупателя сама. Она только **выставляет счёт**, покупатель видит его в Kaspi и подтверждает оплату сам. Отсюда следует:

- Если счёт выставлен, а покупатель не платит — подписка работает правильно
- Лестница ретраев неплательщика не спасёт: она рассчитана на случай, когда счёт **не создался**, а не когда он не оплачен
- Напоминать о неоплаченной подписке нужно со своей стороны

Подробнее: [Бизнес по подписке](/kb/ru/for-subscription-business).

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

**Если остановить подписку, пропадут ли уже выставленные счета?** Нет. Ранее созданные счета живут своей жизнью: будут оплачены, отменены или истекут.

**Можно ли изменить лестницу ретраев?** Да, через поле `retryDelaysMin`, максимум 5 значений. По умолчанию `[15, 60, 360]` минут.

**Можно ли отправить пропущенный запуск вручную?** Да: `POST /subscriptions/{id}/resume` с телом `{ "catchUp": true }`.

**Можно ли включить подписку со статусом `closed`?** Нет, придёт ошибка `subscription_closed`. Создайте новую подписку.

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

**Где полное описание всех полей?** На странице [API подписок](/kb/ru/subscriptions-api).
