Главная Технологии Услуги и цены Кейсы Блог Контакты
К списку статей DevOps и Инфраструктура

Проектирование и разработка SaaS-платформ: Архитектурные паттерны биллинга и подписок

Опубликовано: 28.09.2026 в 15:21

Как построить надежный биллинг для SaaS и не потерять деньги из-за пропущенных вебхуков

Главный источник дохода любой SaaS-платформы — это рекуррентные (автоматические) платежи. В отличие от классического интернет-магазина, где покупка происходит разово, в SaaS жизненный цикл пользователя состоит из множества состояний: триал, активная подписка, задержка платежа (dunning), заморозка и отмена. Написание такой логики «в лоб» через простые флаги в базе данных неизбежно приводит к сбоям: пользователи либо получают бесплатный доступ из-за необработанного отказа банка, либо сталкиваются с ложной блокировкой аккаунта. Мы разберем отказоустойчивую архитектуру биллинга на базе Laravel со строгой обработкой событий от платежных шлюзов.

Архитектура состояний подписки (State Pattern)

Основное правило надежного биллинга — сайт никогда не должен менять статус подписки пользователя на основе действий в интерфейсе. Все изменения должны происходить исключительно по инициативе платежного шлюза (ЮKassa, Stripe, Т-Банк) через асинхронные Webhook-уведомления. Задача бэкенда — развернуть защищенный эндпоинт, который проверяет цифровую подпись каждого входящего запроса от банка, логирует сырой JSON в историю и запускает фоновую задачу (Job) для обновления состояния аккаунта.

Диаграмма прохождения биллингового события
💡 Диаграмма прохождения биллингового событияРис 1.

Шаг 1: Разработка защищенного контроллера обработки вебхуков шлюза

Пишем обработчик событий, который изолирует парсинг входящего пакета от бизнес-логики приложения и гарантирует защиту от атак типа «подмена ответа»

php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Jobs\ProcessSubscriptionWebhook;
use App\Models\WebhookLog;

class BillingWebhookController extends Controller
{
    public function handle(Request $request)
    {
        // Строгая проверка сигнатуры шлюза (пример для Stripe/ЮKassa)
        if (!$this->verifySignature($request)) {
            return response()->json(['error' => 'Invalid signature'], 401);
        }

        // Логируем запрос в базу перед обработкой (fail-safe паттерн)
        $log = WebhookLog::create([
            'event_id' => $request->input('id'),
            'type' => $request->input('type'),
            'payload' => $request->all(),
            'status' => 'pending'
        ]);

        // Отправляем тяжелую логику в фоновую очередь
        ProcessSubscriptionWebhook::dispatch($log);

        // Мгновенно отвечаем банку 200 OK, чтобы он не слал дубли
        return response()->json(['status' => 'success'], 200);
    }
}

Шаг 2: Фоновая обработка состояний подписки в Job-классе

Внутри обработчика очереди мы разбираем тип события и безопасно мутируем даты действия тарифа пользователя, используя встроенные возможности Carbon.

php
<?php

$payload = $this->log->payload;

switch ($payload['type']) {
    case 'invoice.payment_succeeded':
        $user = User::where('stripe_id', $payload['customer_id'])->first();
        $user->subscription()->update([
            'status' => 'active',
            'ends_at' => now()->addMonth(),
        ]);
        $this->log->update(['status' => 'processed']);
        break;

    case 'invoice.payment_failed':
        // Логика dunning-периода (мягкие напоминания и повторные попытки списания)
        break;
}

Итоги и резюме

Главные правила финансовой стабильности SaaS

Построение биллинга через логирование вебхуков и фоновые очереди полностью исключает рассинхронизацию данных. Если ваш сервер кратковременно упадет в момент списания денег, платежная система повторит запрос позже, а система фоновых очередей Laravel Horizon обработает его без потери транзакции. Такой подход защищает бизнес от упущенной выгоды и обеспечивает прозрачный, автоматизированный опыт взаимодействия с платформой для ваших клиентов.

Была ли полезна статья?

Оценки помогают мне понимать, какие темы вам наиболее интересны.

Чтобы оценить, войдите или зарегистрируйтесь.