Как это работает у вас
В терминах парка:
Ваша система биллинга формирует список «водитель → сумма за смену» → выставляет счета через API (по одному или пачкой) → каждый водитель получает push в своём Kaspi → оплатил → ApiPay шлёт вебхук paid → ваша система закрывает задолженность водителя.
Для массового биллинга ApiPay рекомендует ровный поток без залпов: важен не столько дневной объём, сколько равномерность потока во времени. Поэтому надёжнее выставлять счета не по одному в быстром темпе, а пачкой — эндпоинт POST /invoices/bulk: до 100 счетов в одном запросе, лимит 20 запросов/мин. При слишком плотном залпе с одного кассира приём временно замедляется; ApiPay сам распределяет отправку во времени, добавляет адаптивные паузы и ретраит, счета в это время висят в processing — это штатно.
Компоненты ApiPay для массового биллинга
Массовый биллинг опирается на несколько частей Kaspi API:
| Компонент | Зачем парку |
|---|---|
| Счёт по номеру | Водитель получает push; счёт живёт 24 часа |
Идемпотентность (external_order_id_idempotency) |
Один период = один счёт: повтор запроса не создаст дубль (409) |
| Bulk-выставление | POST /invoices/bulk: пачка до 100 счетов одним запросом — равномерная нагрузка без плотных залпов |
Статус processing + вебхуки |
Асинхронная модель: при замедлении система сама распределяет и ретраит выставление |
Вебхук paid/error |
Автозакрытие задолженности; перевыставление только по error |
| Тариф по объёму | Фиксированная подписка под ваш дневной объём (до 30 / до 100 / 100–300 счетов в день; больше 300 — договорная цена) |
Пошаговый сетап
- Зарегистрируйтесь на apipay.kz и опишите объём поддержке (300+/день — обсудите лимиты тарифа заранее).
- Отладьте цикл в песочнице по apipay.kz/docs: список → счета → вебхуки → закрытие задолженности.
- Сразу заложите идемпотентность:
external_order_id_idempotency= стабильный ID начисления. Если ваш внутренний ID длинный и «грязный» (например,A000AA00 за 03.06…) — возьмите от него md5-хэш и передавайте его: слишком длинные значения хуже индексируются. - Подключите номер кассира (требования) и включите рабочий режим.
- Постройте обработку статусов:
paid→ закрыть долг;error→ перевыставить самим;processing→ ждать, ничего не делать. - Спланируйте расписание: большие пачки — bulk-запросом; если объём растёт, разнесите биллинг на две волны (например, по сменам) — важна равномерность потока во времени, а не только общий объём.
Грабли именно массового биллинга
- Двойное списание без идемпотентности. Типичный инцидент: два одинаковых POST с одного ключа, оба получили 201, водитель получил 2 push и оплатил оба. Без
external_order_id_idempotencyкаждый POST — новый живой платёж. С ним повтор получает 409. Это правило №1 для любого биллинга по спискам. - Пересоздание счетов в
processing. Хвост счетов может легитимно висеть вprocessingбольше часа при замедлении — это не зависание. Не пересоздавайте их: получите два живых счёта. Перевыставлять счёт стоит только тогда, когда по нему пришёл вебхук с ошибкой. - Массовые отмены пачки. Симптом «после N счетов всё отменяется» означает слишком плотный залп выставления. Решение — bulk и/или распределение во времени, а не ускорение ретраев.
- Один номер — один кошелёк. Если в списке ошибочный номер, Kaspi может срезолвить его в реальный чужой аккаунт — все счета упадут в один кошелёк, а настоящие водители их не увидят. Валидируйте номера водителей при онбординге.
- Kaspi может сам позвонить крупному бизнесу и предложить официальный API под процент с оборота. Позиция ApiPay здесь честная: если вам предлагают официальный доступ на хороших условиях — это нередко разумнее, речь о финансовых операциях, где важны стабильность и минимум рисков (блокировки, задержки). Сравнивайте экономику: процент с оборота против фиксированной подписки.
Как это выглядит на практике
Типичный сценарий массового биллинга и решения по шагам:
- Задвоение счетов. При выставлении сотен счетов в день бывает, что один и тот же счёт создаётся дважды и водитель оплачивает оба. Решение — идемпотентность: передавайте
external_order_id_idempotency. Если счёт с таким ключом ещё жив (оплачен или вprocessing), система не даст создать дубль. - Длинный внутренний ID. Если идентификатор начисления длинный (например,
A000AA00 за 03.06…), передавайте не его целиком, а md5-хэш от него — так короче и надёжнее для индексации. - Пачки счетов иногда отменяются. Это реакция на слишком плотный залп выставления. Решение — bulk-выставление: не отправлять счета по одному в быстром темпе, а слать пачкой (
POST /invoices/bulk, до 100 за запрос).
Частые вопросы
Можно ли спокойно выставлять сотни счетов в день?
Да: оплаченные счета — обычный оборот. ApiPay сам управляет выставлением — распределяет счета во времени, отправляет пачкой и при необходимости добавляет паузы, — так что вы спокойно выставляете хоть сотни счетов в день, без сбоев.
Нужна ли заявка на официальное партнёрство Kaspi?
Нет. ApiPay — независимый сервис, не официальная интеграция; нужен только открытый счёт Kaspi Pay вашего парка.
Что делать со счётом, который завис в «processing»?
Ничего: система сама ретраит выставление, при замедлении хвост может держаться дольше часа. Перевыставляйте только те счета, по которым пришёл вебхук с ошибкой.
Можно выставить сразу весь список?
Да, пачкой через POST /invoices/bulk — до 100 счетов в одном запросе (лимит 20 запросов/мин). Списки больше — несколькими пачками.
Водители без Kaspi есть — что с ними?
Счёт уйдёт только владельцу Kaspi-аккаунта; для остальных предусмотрите другой канал оплаты и обрабатывайте ошибку client_not_found из вебхука.