Мы не раз сталкивались с проектами, где подписки ломались из-за необработанных webhook’ов: списания срывались, доступ к контенту оставался даже после отмены, а отчётность отсутствовала. В результате компания теряла до 30% выручки только из-за оттока клиентов. Наш опыт в этой области — 8+ лет, за которые мы реализовали более 30 подписочных систем для медиа, SaaS и образовательных платформ. Один из недавних проектов — медиа-сервис с 50 000 платных подписчиков: после перехода на нашу архитектуру отток снизился на 35% за квартал.
Какие проблемы решает система подписок?
Первая и главная — отток клиентов из-за сбоев оплаты. Если списание не удалось, а пользователь не получил уведомление, он теряет доступ и уходит. Мы внедряем grace period и автоматические повторные попытки списания. По данным Stripe, без grace period до 40% клиентов уходят после первой ошибки оплаты; с нашей реализацией этот показатель снижается до 5%. Вторая проблема — неверное выставление счетов при смене тарифа. Пропорциональный расчёт через Stripe решает это. Третья — управление доступом на уровне функций: например, дать доступ к 4K только подписчикам годового плана. Всё закладывается на этапе схемы данных.
Ещё одна частая проблема — идемпотентность webhook. Без уникального ключа повторная отправка события приводит к двойному списанию. Мы реализуем webhook_idempotency_key на уровне базы данных, что исключает дубли.
Почему важен правильный lifecycle подписки?
Жизненный цикл подписки — trialing → active → past_due → expired или cancelled — должен быть строго соблюдён. Каждый статус проверяется на backend: SubscriptionAccessGuard смотрит не только на status, но и на grace_period_ends_at. Это исключает ситуации, когда доступ даётся просроченной подписке. Мы используем Event-driven подход: каждое изменение статуса генерирует событие, на которое подписан уведомитель (email/Telegram).
Как уменьшить отток с помощью grace period?
При неуспешном списании подписка переводится в past_due, запускается grace period (до 7 дней). В этот период доступ полностью сохранён, пользователю отправляется письмо с просьбой обновить платёжные данные. Если оплата не поступает, доступ блокируется, но все данные сохраняются: клиент может восстановить подписку без потери истории. Наша реализация grace period в 2 раза эффективнее стандартной благодаря активным уведомлениям: мы отправляем до 3 писем с разными таймингами.
Как мы реализуем подписки: архитектура и процесс?
Мы используем Laravel (PHP 8.3+) и PostgreSQL. Платёжный провайдер — Stripe или ЮKassa через фабрику PaymentProviderFactory. Все изменения статусов приходят через webhook — это единственный источник правды. Жизненный цикл подписки: trialing → active → past_due → expired или cancelled.
Schema::create('subscription_plans', function (Blueprint $table) { $table->id(); $table->string('name'); $table->string('slug')->unique(); $table->decimal('price_monthly', 10, 2)->nullable(); $table->decimal('price_yearly', 10, 2)->nullable(); $table->integer('trial_days')->default(0); $table->jsonb('features'); $table->boolean('is_active')->default(true); $table->timestamps(); }); Schema::create('subscriptions', function (Blueprint $table) { $table->id(); $table->foreignId('user_id')->constrained(); $table->foreignId('plan_id')->constrained('subscription_plans'); $table->enum('billing_period', ['monthly', 'yearly']); $table->enum('status', ['trialing', 'active', 'past_due', 'cancelled', 'expired']); $table->string('payment_provider'); $table->string('provider_subscription_id')->nullable(); $table->string('provider_customer_id')->nullable(); $table->timestamp('trial_ends_at')->nullable(); $table->timestamp('current_period_start'); $table->timestamp('current_period_end'); $table->timestamp('grace_period_ends_at')->nullable(); $table->timestamp('cancelled_at')->nullable(); $table->timestamp('ends_at')->nullable(); $table->timestamps(); $table->index(['user_id', 'status']); $table->index('current_period_end'); }); Пример создания подписки через CreateSubscriptionAction — транзакция с синхронизацией провайдера и локальной БД. Webhook-обработчик StripeWebhookHandler обрабатывает события invoice.paid, invoice.payment_failed, customer.subscription.updated, customer.subscription.deleted. Контроль доступа — через SubscriptionAccessGuard, который проверяет статус, grace period и features плана.
Какие тарифные модели вы поддерживаете?
Любые: фиксированная цена за период, юнит-подписка (плата за количество объектов, пользователей), freemium с триалом, а также комбинированные — бесплатный уровень с опциями апгрейда. Все модели настраиваются через админ-панель без доработки кода.
Этапы работы
| Этап | Длительность | Описание |
|---|---|---|
| Аналитика | 2–3 дня | Изучение бизнес-логики, моделирование тарифов и лимитов |
| Проектирование | 3–5 дней | Схемы БД, API endpoints, интеграция с платёжным провайдером |
| Реализация | 7–10 дней | Кодинг подписок, webhook, управление доступом |
| Тестирование | 2–3 дня | Покрытие всех сценариев: успешное списание, сбой, апгрейд, отмена |
| Деплой и мониторинг | 1–2 дня | Настройка уведомлений об ошибках, логов webhook |
Что входит в работу?
| Компонент | Описание |
|---|---|
| Схема данных | Таблицы plans, subscriptions, events |
| Платёжная интеграция | Stripe/ЮKassa: подписки, webhook, обработка сбоев |
| Управление доступом | Middleware, guard для проверки features |
| Личный кабинет | UI для смены тарифа, отмены, просмотра истории |
| Уведомления | Email/Telegram о продлении, сбое, истечении grace period |
| Документация | Описание API, инструкция по тестированию |
Типовые ошибки, которые мы предотвращаем: неверная обработка часовых поясов (grace period заканчивается в середине дня), отсутствие логов webhook (сложно дебажить), игнорирование тестовых режимов провайдеров.
Сроки и гарантии
Полный цикл — от 16 до 20 рабочих дней. Мы предоставляем гарантию на корректную работу списаний и обработку webhook в течение 30 дней после сдачи. Все изменения — через git, с code review от старшего разработчика. Подробнее о best practices — в документации Stripe. Свяжитесь с нами для консультации — обсудим вашу бизнес-модель и подберём оптимальное решение. Закажите внедрение системы подписок на вашем проекте.







