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

API подписок — счета по расписанию

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

Коротко

Подписка — это автоматическое выставление счетов по расписанию. Деньги с карты покупателя сами не уходят: в каждом периоде создаётся новый счёт, он приходит покупателю, и каждую оплату покупатель подтверждает сам. Автоматизируется у вас другое — своевременный выпуск счёта и повтор неудачных попыток.

Минимальный пример:

POST /api/v1/subscriptions
X-API-Key: qp_live_…
Content-Type: application/json

{
  "amount": 9900,
  "interval": "month",
  "every": 1,
  "kind": "phone",
  "customer": { "phone": "77011234567", "name": "Айдана" }
}

Ключу нужно право subscriptions:manage.

Что автоматизируется, а что нет

АвтоматическиВручную / покупателем
Выпуск счёта по расписаниюОплату подтверждает покупатель
Повтор неудачной попыткиСмена суммы — через изменение подписки
Обработка пропущенного запускаРешение остановить подписку
Отправка событий (вебхуки)Возврат денег

То есть подписка — это расписание, которое помнит клиента и вовремя выставляет счёт, а не механизм списания средств.

Создание: все поля

ПолеТипОписание
amountnumber, обязательноСумма одного периода, тенге
intervalday \week \monthЕдиница интервала
everyintegerКратность: interval: month, every: 3 — раз в квартал
kindqr \phoneТип счёта. phone — в приложение Kaspi покупателя
customer.phone / .name / .emailstringПри kind: phone телефон обязателен
dayOfMonthintegerВ какой день месяца выставлять счёт
startAtdate-timeКогда первый запуск
maxRunsintegerМаксимум запусков. По достижении подписка закрывается
retryDelaysMinnumber[]Лестница повторов в минутах. По умолчанию [15, 60, 360], не больше 5 значений
misfirePolicyrun_once \skipЧто делать с пропущенным запуском. По умолчанию run_once
misfireAfterMinintegerЧерез сколько минут запуск считается пропущенным. По умолчанию 1440
descriptionstringПокупатель видит в счёте
metadataobjectЛюбой JSON, переносится в счёт

Каждый созданный счёт несёт поля metadata.subscriptionId и metadata.run — по ним в отчёте видно, какой подписке и какому периоду принадлежит платёж.

Лестница повторов

Выпуск счёта может не удаться: Kaspi не ответил, оборвалась привязка кассира, закончился лимит тарифа. Тогда подписка повторяет попытку по лестнице retryDelaysMin.

Значение по умолчанию [15, 60, 360] — через 15 минут, затем через 1 час, затем через 6 часов.

ЗначениеЧто происходит
[15, 60, 360]Три повтора: 15 мин, 1 ч, 6 ч
[5, 5, 5, 5, 5]Пять повторов каждые 5 минут (5 значений — максимум)
[]Повторов нет, запуск отбрасывается после первой неудачи

Когда лестница закончилась, этот запуск отбрасывается, но подписка не закрывается — расписание продолжается со следующего периода. О неудаче приходит уведомление в Telegram или на email.

Политика пропуска

Запуск может не выполниться вовремя: подписка стояла на паузе, был долгий перерыв. Что делать в этом случае, решает misfirePolicy:

ЗначениеПоведение
run_once (по умолчанию)Опоздавший запуск выполняется один раз, несколько пропущенных схлопываются в один
skipЕсли опоздание больше misfireAfterMin (по умолчанию 1440 минут = сутки), запуск пропускается, расписание идёт дальше

Хотите всё-таки получить оплату за пропущенный период — оставляйте run_once. Считаете, что устаревший счёт только запутает покупателя — ставьте skip.

Методы управления

МетодЧто делает
POST /api/v1/subscriptionsСоздаёт подписку
GET /api/v1/subscriptionsСписок
GET /api/v1/subscriptions/{id}Одна подписка с полным состоянием
PATCH /api/v1/subscriptions/{id}Меняет сумму, интервал, политику и другие поля
POST /api/v1/subscriptions/{id}/pauseСтавит расписание на паузу
POST /api/v1/subscriptions/{id}/resumeВозобновляет
POST /api/v1/subscriptions/{id}/cancelЗакрывает окончательно
POST /api/v1/subscriptions/{id}/runВыставляет внеочередной счёт

У resume есть важный нюанс:

POST /api/v1/subscriptions/sub_9Qp1/resume
{ "catchUp": true }

С catchUp: true пропущенный за время паузы запуск выполняется сразу. По умолчанию (без catchUp или с false) расписание просто продолжается со следующей плановой даты.

Поля состояния

В ответе GET /api/v1/subscriptions/{id} видно текущее положение дел:

ПолеЗначение
nextRunAtКогда выйдет следующий счёт
runsСколько запусков выполнено
failedRunsСколько запусков завершились неудачей
retryAttemptКакая по счёту попытка идёт по текущему запуску
lastRunStatusok \retrying \failed \skipped
lastErrorКод последней ошибки
lastInvoiceIdПоследний созданный счёт

Если по подписке не выставляются счета, диагностику начинайте именно отсюда: lastRunStatus и lastError сразу называют причину. Подробный разбор: Подписка не выставляет счета.

Кассир

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

Коды ошибок

КодHTTPЧто случилось
invalid_interval422interval не day, week или month
invalid_every422every не положительное целое
invalid_retry422retryDelaysMin неверный: больше 5 значений или отрицательные числа
invalid_misfire422misfirePolicy не run_once и не skip
invalid_max_runs422Неверный maxRuns
subscription_closed409Подписка завершена или остановлена
subscription_not_found404Идентификатор не найден
insufficient_scope403У ключа нет права subscriptions:manage

События

subscription.created — подписка создана, subscription.status — изменилось состояние. Кроме того, по каждому выставленному счёту приходят обычные события invoice.created, invoice.paid и остальные. Факт оплаты вы узнаёте из invoice.paid, а принадлежность к подписке — из metadata.subscriptionId.

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

Что будет, если покупатель не заплатит? Счёт просто останется неоплаченным и перейдёт в expired. Подписка выставит новый счёт в следующем периоде. Решение отключить доступ к услуге принимаете вы.

Можно ли поменять сумму? Да, через PATCH. Новая сумма применяется со следующего запуска.

QR или phone — что выбрать? Для подписки чаще удобнее phone: счёт приходит прямо в приложение Kaspi. Разбор различий: QR-счёт или счёт по телефону.

Можно ли вернуть деньги по подписке? Да, как обычно — возврат делается по конкретному счёту: API возвратов.

Можно ли всё это проверить в песочнице? Да. Создайте подписку, вызовите run для внеочередного счёта и симулируйте оплату.

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

Подписка не выставляет счетаЕсли подписка не создаёт счета по расписанию, проверить нужно шесть вещей: статус, время следующего запуска, лестницу ретраев, политику пропуска, кассира и лимит тарифа. Где смотреть lastRunStatus и lastError.Каталог ошибок — что возвращает API и что делатьВсе основные коды ошибок Qut Pay API по группам: авторизация, привязка Kaspi, счета, возвраты, лимиты тарифа, вебхуки, подписки. Причина и решение для каждой.Права доступа (scopes) — что может ключПолная таблица шести scope: invoices:read, invoices:write, refunds:write, subscriptions:manage, webhooks:manage, partner:manage. Какие методы открывает каждый, принцип минимальных прав и разбор ошибки insufficient_scope.QR-счёт или счёт по телефону — что выбратьПолное сравнение двух типов счёта: значение kind, что делает покупатель, нужен ли номер, ограничения описания и суммы, срок жизни и таблица сценариев с рекомендацией по каждому.API возвратов — полный и частичный возвратСправочник по методу POST /invoices/{id}/refund: поля запроса, полный и частичный возврат, ограничение суммы, все коды ошибок, что делать при refund_unknown и какие события приходят после возврата.

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

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