Представьте: вы запускаете SaaS, через месяц — 1000 пользователей, каждый с разным планом, часть на триале, часть отменяет. Без биллинговой системы хаос. Stripe Billing — готовое решение, которое покрывает 95% сценариев: подписки, пробные периоды, апгрейды/даунгрейды, prorated billing, метерированное потребление, автоматический retry при неудаче. В отличие от самописной системы, Stripe Billing сокращает время разработки с 2–3 месяцев до 1–2 недель — это в 5–10 раз быстрее. И минимизирует ошибки за счёт проверенных алгоритмов. Экономия на разработке — от $15 000, а на поддержке — $5 000 в год. Мы интегрировали Stripe в 30+ проектах, гарантируя стабильную работу биллинга под ключ. Наш опыт позволяет предсказать и избежать типичных проблем: некорректная обработка trial, ошибки prorating, сбои в вебхуках.
Ключевые сущности
Product → Price → Subscription → Invoice → PaymentIntent. Продукт — план (Basic, Pro, Enterprise). К нему привязываются цены (месячная/годовая). Подписка привязывает customer к цене. Invoice выставляется автоматически.
Как Stripe Billing решает проблему биллинга?
Stripe берет на себя всю рутину: создание инвойсов, попытки списания, prorating, trial. Вам нужно лишь настроить продукты и вебхуки для синхронизации статусов. Это сокращает время разработки с месяцев до 1–2 недель.
Создание продуктов и цен
$product = \Stripe\Product::create([
'name' => 'Pro Plan',
'metadata' => ['plan_id' => 'pro'],
]);
$monthlyPrice = \Stripe\Price::create([
'product' => $product->id,
'unit_amount' => 2900,
'currency' => 'usd',
'recurring' => ['interval' => 'month'],
'lookup_key' => 'pro_monthly',
]);
$yearlyPrice = \Stripe\Price::create([
'product' => $product->id,
'unit_amount' => 27900,
'currency' => 'usd',
'recurring' => ['interval' => 'year'],
'lookup_key' => 'pro_yearly',
]);
Регистрация пользователя и создание подписки
Процесс состоит из четырёх шагов: создание Stripe-клиента, создание подписки с trial, передача client_secret на фронтенд, обработка вебхуков. Рассмотрим каждый.
$stripeCustomer = \Stripe\Customer::create([
'email' => $user->email,
'name' => $user->name,
'metadata' => ['user_id' => $user->id],
]);
$subscription = \Stripe\Subscription::create([
'customer' => $user->stripe_customer_id,
'items' => [['price' => 'pro_monthly']],
'trial_period_days' => 14,
'payment_behavior' => 'default_incomplete',
'payment_settings' => ['save_default_payment_method' => 'on_subscription'],
'expand' => ['latest_invoice.payment_intent'],
]);
$clientSecret = $subscription->latest_invoice->payment_intent->client_secret;
payment_behavior: default_incomplete — подписка активируется только после успешного первого платежа. Важно для бесплатных trial: карта привязывается, но не списывается.
Апгрейд/даунгрейд
public function changePlan(User $user, string $newPriceLookupKey): void
{
$prices = \Stripe\Price::all(['lookup_keys' => [$newPriceLookupKey]]);
$newPrice = $prices->data[0];
$subscription = \Stripe\Subscription::retrieve($user->stripe_subscription_id);
\Stripe\Subscription::update($subscription->id, [
'items' => [[
'id' => $subscription->items->data[0]->id,
'price' => $newPrice->id,
]],
'proration_behavior' => 'create_prorations',
'billing_cycle_anchor'=> 'unchanged',
]);
}
При апгрейде с proration Stripe автоматически кредитует неиспользованное время и выставляет invoice на разницу. Годовая подписка — proration_behavior: none.
Почему стоит использовать Stripe Customer Portal?
Готовый UI для управления подпиской: смена карты, отмена, история инвойсов. Не нужно писать с нуля. Достаточно создать сессию BillingPortal.Session и перенаправить пользователя. Это экономит до 40 часов разработки интерфейса.
Webhook: синхронизация статусов
Вся бизнес-логика строится на вебхуках, а не на синхронных ответах API. Основные события:
| Событие | Действие |
|---|---|
| customer.subscription.created | Сохранить subscription_id, активировать пользователя |
| customer.subscription.updated | Обновить статус в БД |
| customer.subscription.deleted | Отметить как отменённую |
| invoice.payment_succeeded | Обновить дату next_payment |
| invoice.payment_failed | Уведомить пользователя, не блокировать сразу |
| customer.subscription.trial_will_end | Напомнить о скором списании |
Также важно обрабатывать customer.subscription.paused и resumed, если поддерживаете паузу.
protected array $handlers = [
'customer.subscription.created' => 'onSubscriptionCreated',
'customer.subscription.updated' => 'onSubscriptionUpdated',
'customer.subscription.deleted' => 'onSubscriptionCancelled',
'invoice.payment_succeeded' => 'onInvoicePaid',
'invoice.payment_failed' => 'onInvoicePaymentFailed',
'customer.subscription.trial_will_end'=> 'onTrialEndingSoon',
];
public function onInvoicePaymentFailed(array $event): void
{
$subscription = $event['data']['object']['subscription'];
$user = User::where('stripe_subscription_id', $subscription)->firstOrFail();
$nextRetry = $event['data']['object']['next_payment_attempt'];
Notification::send($user, new PaymentFailedNotification($nextRetry));
}
Как обрабатывать неудачные платежи?
Stripe автоматически делает до 3 попыток списания с интервалами 2, 3 и 5 дней. Ваша задача — уведомлять пользователя и обновлять статус подписки на past_due. После третьей неудачи подписка переходит в canceled. Чтобы избежать потери клиентов, реализуйте сценарий: при первой неудаче — письмо, при второй — push-уведомление, при третьей — блокировка доступа с возможностью продления.
Metered billing
Для оплаты по потреблению (API вызовы, хранилище):
$price = \Stripe\Price::create([
'product' => $product->id,
'currency' => 'usd',
'recurring' => [
'interval' => 'month',
'usage_type' => 'metered',
'aggregate_usage'=> 'sum',
],
'billing_scheme' => 'per_unit',
'unit_amount' => 1,
]);
\Stripe\SubscriptionItem::createUsageRecord(
$subscriptionItemId,
['quantity' => $apiCallsThisPeriod, 'action' => 'set']
);
action: set — абсолютное значение, increment — добавить к текущему. set безопаснее при retry.
Сравнение моделей биллинга
| Параметр | Flat-rate | Per-unit | Tiered |
|---|---|---|---|
| Сложность реализации | Низкая | Средняя | Высокая |
| Гибкость для клиента | Низкая | Высокая | Средняя |
| Риск ошибок prorating | Минимальный | Средний | Высокий |
| Рекомендуется для | Базовые планы | API, хранилище | Enterprise |
Чек-лист для безопасной интеграции вебхуков
- Подтверждайте событие по подписи (Webhook-Signature header).
- Идемпотентность: используйте
idempotency_keyпри создании подписок. - Логируйте все вебхуки для отладки.
- Добавьте health-check endpoint для мониторинга.
- Тестируйте сценарии: успешный платёж, неудача, trial, апгрейд.
Что входит в работу
- Настройка продуктов и цен в Stripe Dashboard.
- Создание миграций для синхронизации планов.
- Реализация регистрации и создания подписки с trial.
- Настройка вебхуков и обработка ключевых событий.
- Интеграция Customer Portal.
- Документация по API и пост-релизная поддержка 1 месяц.
Как гарантировать 99.9% uptime биллинга?
Используйте failover-логику: если Stripe API недоступен, кешируйте запросы и повторяйте их с экспоненциальной задержкой. Настройте мониторинг вебхуков с оповещением в Telegram/Slack. Всегда обрабатывайте события invoice.payment_failed — это снижает churn на 20% при своевременном уведомлении.
Свяжитесь с нами для точной оценки вашего проекта. Базовая интеграция — от 5 до 10 рабочих дней. Сложные сценарии (metered billing, несколько валют) — до 3 недель. Получите консультацию по интеграции Stripe Billing — настройте биллинг под ваш SaaS без головной боли.







