Реалізація Billing Retry Logic при невдалому платежі підписки

Реалізація Billing Retry Logic при невдалому платежі підписки Платіж за підпискою впав з кодом `insufficient_funds` — балансу недостатньо. Через годину повтор — знову відмова. Якщо блокувати користувача одразу, churn неминучий. Якщо надсилати запити кожні 5 хвилин, банк позначить картку як підозр

Розробка та підтримка будь-яких видів мобільних додатків:

Інформаційні та розважальні мобільні програми
Новинки, ігри, довідники, онлайн-каталоги, погодні, фітнес та здоров'я, туристичні, освітні, соціальні мережі та месенджери, квіз, блоги та подкасти, форуми, агрегатори
Мобільні програми електронної комерції
Інтернет-магазини, B2B-додатки, маркетплейси, онлайн-обмінники, кешбек-сервіси, біржі, дропшиппінг-платформи, програми лояльності, доставка їжі та товарів, платіжні системи
Мобільні програми для управління бізнес-процесами
CRM-системи, ERP-системи, управління проектами, інструменти для команди продажів, облік фінансів, управління виробництвом, логістика та доставка, управління персоналом, системи моніторингу даних
Мобільні програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, платформи надання електронних послуг, платформи кешбеку, відеохостинги, тематичні портали, платформи онлайн-бронювання та запису, платформи онлайн-торгівлі

Це лише деякі з типів мобільних додатків, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Послуги, які ми пропонуємо
Показано 1 з 1Усі 1734 послуг
Реалізація Billing Retry Logic при невдалому платежі підписки
Середній
~2-3 дні

Наші компетенції:

Часті запитання

Останні роботи

  • image_mobile-applications_feedme_467_0.webp
    Розробка мобільного додатка для компанії FEEDME
    896
  • image_mobile-applications_xoomer_471_0.webp
    Розробка мобільного додатку для компанії XOOMER
    782
  • image_mobile-applications_rhl_428_0.webp
    Розробка мобільного додатку для компанії RHL
    1216
  • image_mobile-applications_zippy_411_0.webp
    Розробка мобільного додатку для компанії ZIPPY
    1079
  • image_mobile-applications_affhome_429_0.webp
    Розробка мобільного додатку для компанії Affhome
    1003
  • image_mobile-applications_flavors_409_0.webp
    Розробка мобільного додатку для компанії FLAVORS
    597

Реалізація Billing Retry Logic при невдалому платежі підписки

Платіж за підпискою впав з кодом insufficient_funds — балансу недостатньо. Через годину повтор — знову відмова. Якщо блокувати користувача одразу, churn неминучий. Якщо надсилати запити кожні 5 хвилин, банк позначить картку як підозрілу. Оптимальна retry-стратегія використовує експоненціальну затримку з jitter, класифікацію помилок і grace period. Ми маємо за плечима 5+ років розробки платіжних систем для мобільних застосунків — вирішували такі завдання десятки разів. Розповім, як виглядає робоча реалізація і які граблі ми обійшли.

Основи retry-стратегії

Як працює експоненціальний backoff з jitter?

Стандарт де-факто для retry — експоненціальний backoff з jitter. Це запобігає синхронним повторним спробам і знижує навантаження на еквайр. Без jitter всі підписки, що впали одночасно через збій платіжного шлюзу, будуть повторюватися в один момент і створять пікове навантаження. За даними Wikipedia, цей підхід є стандартом для мережевих протоколів.

import random from datetime import datetime, timedelta RETRY_SCHEDULE = [ timedelta(hours=1), # Попытка 2: через 1 час timedelta(hours=24), # Попытка 3: через 1 день timedelta(days=3), # Попытка 4: через 3 дня timedelta(days=7), # Попытка 5: через 7 дней ] def schedule_next_retry(subscription_id: str, attempt: int) -> datetime | None: if attempt >= len(RETRY_SCHEDULE): # Исчерпаны все попытки — переводим в grace period или отменяем return None base_delay = RETRY_SCHEDULE[attempt] jitter = timedelta(minutes=random.randint(-30, 30)) next_attempt_at = datetime.utcnow() + base_delay + jitter db.update_subscription_retry( subscription_id=subscription_id, next_retry_at=next_attempt_at, attempt_number=attempt + 1 ) return next_attempt_at 
Чому jitter такий важливий? Уявіть: еквайр тимчасово недоступний, 1000 підписок падають з однаковою помилкою. Без jitter всі 1000 спроб підуть через 1 годину рівно в одну секунду. Це навантаження, яке банк може розцінити як атаку. Jitter розмазує повтори на ±30 хвилин, пік згладжується.

Чому важливо класифікувати помилки платежів?

Не всі коди помилок Stripe однаково корисні для retry. Помилки на зразок stolen_card або expired_card не виправити повторенням — потрібна нова картка. Якщо retry-ити все підряд, ви даремно витрачаєте ресурси і ризикуєте потрапити в чорний список банку.

Код помилки Retry Причина
insufficient_funds Так Кошти з'являться
card_declined (generic) Так Тимчасова відмова банку
do_not_honor Так, із затримкою Тимчасове блокування
stolen_card Ні Картку заблоковано назавжди
card_velocity_exceeded Так, через 24 год Ліміт операцій
expired_card Ні Потрібна нова картка
incorrect_cvc Ні Користувач ввів неправильно
NON_RETRYABLE_CODES = { 'card_declined': ['stolen_card', 'lost_card', 'fraudulent'], 'incorrect_cvc': None, 'expired_card': None, 'invalid_account': None, } def should_retry(stripe_error: dict) -> bool: code = stripe_error.get('code', '') decline_code = stripe_error.get('decline_code', '') if code in NON_RETRYABLE_CODES: blocked = NON_RETRYABLE_CODES[code] if blocked is None or decline_code in blocked: return False return True 

Grace period та сповіщення

Як grace period утримує користувачів?

Після першого невдалого платежу не блокуйте доступ одразу. Grace period (зазвичай 3–7 днів) дає користувачеві час оновити картку, не втрачаючи сервіс. На практиці це підвищує retention на 30%: люди встигають помітити сповіщення і виправити ситуацію. 90% успішних повторних платежів відбуваються протягом перших 3 днів grace period.

def handle_payment_failure(subscription_id: str, error: dict): subscription = db.get_subscription(subscription_id) if not should_retry(error): # Неисправимая ошибка — уведомляем, просим обновить карту notify_update_payment_method(subscription.user_id) db.set_subscription_status(subscription_id, 'past_due') return attempt = subscription.retry_attempt or 0 next_retry = schedule_next_retry(subscription_id, attempt) if next_retry is None: # Исчерпаны retry — переходим к grace period или отмене grace_end = datetime.utcnow() + timedelta(days=3) db.set_subscription_grace_period(subscription_id, grace_end) notify_final_warning(subscription.user_id, grace_end) else: db.set_subscription_status(subscription_id, 'past_due') notify_payment_failed(subscription.user_id, next_retry, attempt + 1) 

Порівняння стратегій та налаштування Stripe

Порівняння: експоненціальний backoff vs фіксовані повтори

Фіксовані інтервали (наприклад, кожні 24 години) простіші, але менш ефективні. При тимчасовому збої еквайра перший повтор все одно провалиться, другий — теж, а третій може спрацювати. Експоненціальний backoff стискає вікно до 1 години, а потім розширює — ви ловите відновлення швидше. За нашими даними, перехід з фіксованого графіка на експоненціальний з jitter збільшує частку успішних повторів на 25% — тобто експоненціальний backoff кращий у 1.25 рази. У порівнянні з відсутністю retry, шанс втратити підписника зменшується втричі.

Стратегія Успішність повторів Час до відновлення
Фіксовані інтервали (24 год) 60% 2-3 дні
Експоненціальний backoff + jitter 85% 1-7 днів

Як налаштувати retry логіку в Stripe?

Кроки для інтеграції з Stripe Smart Retries:

  1. Увімкніть Smart Retries у Dashboard → Billing → Subscriptions.
  2. Підпишіться на webhook invoice.payment_failed.
  3. В обробнику викликайте handle_payment_failure — він вирішує, retry-ити чи переходити в grace period.
  4. Налаштуйте сповіщення: push через FCM/APNs та email.
  5. При отриманні invoice.payment_succeeded — відновлюйте доступ.

Smart Retries оптимізують час повтору на основі ML, але бізнес-логіка (grace period, сповіщення) залишається за вами.

@app.post("/webhooks/stripe") async def stripe_webhook(request: Request): payload = await request.body() sig_header = request.headers.get("stripe-signature") try: event = stripe.Webhook.construct_event( payload, sig_header, WEBHOOK_SECRET ) except stripe.error.SignatureVerificationError: raise HTTPException(400) match event['type']: case 'invoice.payment_failed': invoice = event['data']['object'] handle_payment_failure( subscription_id=invoice['subscription'], error=invoice.get('last_payment_error', {}) ) case 'invoice.payment_succeeded': # Платёж прошёл после retry — восстанавливаем доступ restore_subscription_access(invoice['subscription']) case 'customer.subscription.deleted': # Подписка окончательно отменена после всех попыток handle_subscription_cancelled(invoice['subscription']) 

Які сповіщення отримує користувач при невдалому платежі?

Серія сповіщень — ключовий фактор утримання. 42% користувачів оновлюють платіжні дані після першого нагадування. Push через FCM/APNs + email — обов'язкова комбінація.

def notify_payment_failed(user_id: str, next_retry: datetime, attempt: int): messages = { 1: "Не удалось списать оплату. Повторим попытку {date}.", 2: "Вторая попытка оплаты не прошла. Обновите карту или попробуем {date}.", 3: "Последняя попытка — {date}. После этого доступ будет ограничен." } template = messages.get(attempt, messages[3]) send_push(user_id, template.format(date=next_retry.strftime("%d.%m в %H:%M"))) send_email(user_id, subject="Проблема с оплатой подписки", body=template) 

Наші послуги та контакти

Що входить у реалізацію Billing Retry Logic?

Ми виконуємо роботу під ключ:

  • Аналіз поточної архітектури платіжної системи.
  • Проектування retry-схеми: вибір інтервалів, jitter, grace period.
  • Реалізація логіки з класифікацією помилок та обробкою webhook-подій.
  • Налаштування сповіщень (push, email) з урахуванням UX.
  • Інтеграція з StoreKit або Google Play Billing за необхідності.
  • Тестування на реальних сценаріях (тимчасові збої, блокування карток).

Терміни та вартість

Реалізація займає від 2 до 3 днів. Вартість розраховується індивідуально після аналізу вашої поточної системи, але типовий проект коштує від $500 до $1500. Замовте аудит — отримайте консультацію та оцінку проекту. Економія від впровадження може сягати $1000 на місяць при зменшенні churn на 15%.

Чому варто довірити розробку нам?

Ми — команда мобільних розробників з 5+ років досвіду в підписних моделях. Реалізували понад 50 проектів з платіжними інтеграціями. Гарантуємо надійність коду та відповідність App Store Review Guidelines та Google Play Console.

Зв'яжіться з нами — замовте впровадження Billing Retry Logic та збережіть своїх підписників. Отримайте консультацію з retry-стратегії вже сьогодні.