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

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

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

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

  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 ₸ и только целые тенге (дробную сумму создание подписки примет, но каждое списание уйдёт в error с amount_must_be_whole_tenge); 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.

Подпискам нужна верифицированная организация: без неё API отвечает 400 Subscriptions require a verified organization.

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

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

После expired реактивации не существует — ни кнопки, ни метода API. Покупатель вернулся через месяц? Создайте новую подписку.

Отдельная причина тишины — ваш собственный тариф ApiPay. Если тариф не оплачен (403 tariff_inactive) или включено ограничение по дневному лимиту (429 tariff_limit_reached), автосписание пропускает цикл молча: счёт покупателю не выставляется, дата следующего списания не сдвигается, счётчик неудачных попыток не растёт, вебхука об этом нет. После оплаты тарифа или снятия ограничения подписки догоняют пропущенные периоды — по одному за прогон. См. Лимит счетов по тарифу.

Пауза устроена мягче: 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 — это тоже неуспешная попытка: приходит subscription.payment_failed, в payload добавляется error_code. Если ошибка на стороне сервиса (например, оборвалась Kaspi-сессия), попытка не засчитывается и период сохраняется — следующая попытка будет позже. Если причина в плательщике (client_not_found — у номера нет Kaspi), идут обычные ретраи и затем grace.

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

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

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

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

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

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

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

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

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

Скопируйте готовый промпт и вставьте своему ИИ-ассистенту — он настроит интеграцию за вас: получит доступы, создаст тестовый счёт в песочнице и подключит вебхуки. Техническую часть делает ИИ, а не вы.

Остались вопросы — напишите нам в WhatsApp: +7 700 307 65 12. Отвечаем быстро, без звонков.

Написать в WhatsApp

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