Подписки ApiPay: есть ли автосписание с покупателя?

Обновлено 6 июля 2026 · Справочник · Версия в Markdown
Содержание
  1. Как на самом деле работает подписка (и почему это удобно покупателю)
  2. Создание подписки через API
  3. Что происходит, когда покупатель не платит?
  4. События subscription.* для интеграции
  5. Частые ошибки
  6. Вопросы и ответы

Как на самом деле работает подписка (и почему это удобно покупателю)

Аналогия для трека «на пальцах»: подписка ApiPay — это не «рука в кармане покупателя», а пунктуальный бухгалтер, который каждый месяц сам выписывает счёт и вежливо напоминает, если его не оплатили.

Цикл выглядит так:

  1. Вы создаёте подписку: номер телефона покупателя + период + сумма.
  2. В расчётную дату система сама создаёт обычный счёт Kaspi — покупателю приходит push в приложение Kaspi.
  3. Покупатель нажимает «Оплатить» — деньги, как всегда, идут напрямую на ваш Kaspi-счёт. Вам приходит вебхук subscription.payment_succeeded.
  4. Дата следующего выставления сдвигается на период — и так по кругу.

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

Создание подписки через API

curl -X POST "https://api.apipay.kz/api/v1/subscriptions" \
  -H "X-API-Key: ВАШ_КЛЮЧ" \
  -H "Content-Type: application/json" \
  -d '{
    "phone_number": "87001234567",
    "amount": 15000,
    "billing_period": "monthly",
    "billing_day": 1,
    "description": "Абонемент, тариф Стандарт"
  }'

Параметры и границы: billing_perioddaily | weekly | biweekly | monthly | quarterly | yearly; amount — от 100 до 1 000 000 ₸; billing_day — 1–28 (чтобы дата существовала в любом месяце); max_retry_attempts — 1–10 (по умолчанию 3); retry_interval_hours — 1–168 (по умолчанию 24); grace_period_days — 1–30 (по умолчанию 3); bill_immediately — выставить первый счёт сразу при создании.

Важная деталь, о которую спотыкаются: ответ 201 на POST /subscriptions означает «подписка создана», а не «покупателю уже ушёл счёт». Если вы ждёте немедленный push покупателю — передайте bill_immediately: true. Управление: POST /subscriptions/{id}/pause | resume | cancel, счета подписки — GET /subscriptions/{id}/invoices.

Что происходит, когда покупатель не платит?

Здесь подписка отрабатывает за вас всю рутину «дожима»:

  1. Счёт не оплачен (истёк через 24 часа или отменён) → вам приходит subscription.payment_failed с причиной (Invoice expired / Invoice cancelled) и номером попытки.
  2. Система сама перевыставляет счёт — по умолчанию до 3 попыток с интервалом 24 часа. Вручную ничего пересоздавать не нужно (и не надо: получите два параллельных счёта).
  3. Попытки исчерпаны → начинается grace-период (subscription.grace_period_started, по умолчанию 3 дня): доступ покупателю вы пока не отключаете, а любая его оплата немедленно возвращает подписку в норму.
  4. Grace истёкsubscription.expired: биллинг по этой подписке остановлен навсегда.

После expired реактивации не существует — ни кнопки, ни метода API. Покупатель вернулся через месяц? Создайте новую подписку. Это осознанное правило: «воскрешение» старой подписки означало бы споры о пропущенных периодах и неожиданные счета.

Пауза устроена мягче: pause останавливает выставление, resume продолжает от текущего момента — пропущенные периоды не доначисляются, покупателю не прилетит «счёт за три месяца тишины». cancel — безвозвратен, как и expired.

События subscription.* для интеграции

Вебхуки подписок приходят на тот же URL, что и счета (настройка — «Настройка вебхуков ApiPay»):

Событие Когда Доп. поля (в корне payload)
subscription.created Подписка создана
subscription.payment_succeeded Счёт подписки оплачен invoice_id, amount, paid_at
subscription.payment_failed Счёт истёк/отменён invoice_id, amount, reason, attempt_number
subscription.grace_period_started Ретраи исчерпаны grace_period_days, expires_at
subscription.expired Grace истёк, биллинг остановлен
subscription.paused / resumed / cancelled Соответствующие действия

Три инженерных нюанса (трек D):

  • Дедупликация обязательна: у событий подписок нет защиты от дублей — дедуплицируйте по (event, subscription.id, invoice_id).
  • Ретраев в логах не ищите: события subscription.* не попадают в webhook-логи кабинета и не имеют ручного перезапуска — отвечайте 200 быстро и обрабатывайте асинхронно.
  • Известное ограничение: если счёт подписки завершился статусом error (например, client_not_found — у номера нет Kaspi), это не считается провалом оплаты: payment_failed не придёт, ретрая не будет, период будет пропущен. Отлавливайте такие случаи по invoice.status_changed со статусом error для счетов подписки.

Частые ошибки

  • Обещать клиентам «автосписание как у Netflix». Не обещайте: покупатель подтверждает каждый платёж сам. Честная формулировка — «счёт будет приходить автоматически, оплата в один клик».
  • Пересоздавать счёт вручную после payment_failed. Система сама ретраит по расписанию — ручной счёт даст дубль.
  • Ждать payment_failed при счёте в статусе error. Не придёт (известное ограничение) — мониторьте error-счета подписок отдельно.
  • Пытаться реактивировать expired-подписку. Невозможно by design — создайте новую.
  • Ставить billing_day: 29–31. API не примет: допустимы 1–28, чтобы дата существовала в феврале.
  • Тестировать подписки в песочнице без организации. Подпискам нужна верифицированная организация — API ответит 400 Subscriptions require a verified organization.

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

Почему нельзя сделать настоящее автосписание?

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

Чем подписка отличается от разового счёта?

Разовый счёт вы создаёте сами каждый раз. Подписка создаёт такие же счета автоматически по расписанию, сама ретраит неоплату, ведёт grace-период и шлёт события subscription.*.

Покупатель оплатил в grace-периоде — что дальше?

Подписка возвращается в нормальный цикл: grace снимается, следующий счёт придёт по обычному расписанию.

Можно ли изменить сумму действующей подписки?

Да, через PUT /subscriptions/{id} — изменения применяются к будущим счетам.

Как поставить подписку на паузу на время отпуска клиента?

POST /subscriptions/{id}/pause, затем resume — выставление продолжится от текущей даты, пропущенные периоды не доначисляются.

Подписка умерла (expired) — я потеряю историю?

Нет: подписка и все её счета остаются в кабинете и API. Остановлен только будущий биллинг — для продолжения создайте новую подписку.

Интеграция с ИИ

Не настраивайте вручную — поручите ИИ

Скопируйте готовый промпт и вставьте своему ИИ-ассистенту — он подключит приём платежей примерно за 15 минут. Настраивает ИИ, а не вы.

Остались вопросы — напишите нам в WhatsApp: +7 708 516 74 89. Отвечаем быстро, без звонков.

Написать в WhatsApp

Для разработчика. Полная спецификация API — apipay.kz/docs. Эта статья в Markdown — /guides/podpiski-apipay.md. Справочник фактов для ИИ-агента — apipay.kz/llms.txt.