Настройка Webhook-системы: управление подписками

Когда бизнес растёт, статическая настройка webhook-уведомлений перестаёт справляться: сложно добавлять новых получателей, управлять правами и отслеживать доставку. Мы разрабатываем REST API для управления подписками, который автоматизирует весь процесс — от регистрации эндпоинтов до ротации секретов и автоотключения неактивных. Наша команда реализует проект под ключ, обеспечивая надёжную работу и последующую поддержку.

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Услуги, которые мы предлагаем
Показано 1 из 1Все 2062 услуг
Настройка Webhook-системы: управление подписками
Средний
~2-3 дня
Часто задаваемые вопросы

Представьте: ваш интернет-магазин обрабатывает 1000 заказов в день, и каждый заказ нужно передать в CRM, складскую систему, сервис аналитики и два партнёрских API. Статически прописанные webhook-эндпоинты в конфиге — решение для MVP, но при масштабировании вы столкнётесь с ростом числа получателей и необходимостью дать клиентам самостоятельно управлять подписками. Мы создаём REST API для управления webhook-подписками, которое решает эти проблемы. Наш опыт — 5+ лет и более 50 проектов с webhook-интеграциями, гарантируем 99.9% uptime и стабильную доставку событий до 10 000 в секунду. Поддержка после внедрения включена.

Допустим, у вас уже есть система событий (например, на Laravel), и вы хотите добавить возможность подписки внешних сервисов. Наш подход: проектируем базу данных подписок, REST API для управления, и механизмы доставки с повторными попытками и мониторингом. Всё это под ключ за 1-1.5 недели. Закажите консультацию, чтобы обсудить ваш сценарий.

Почему статическая конфигурация webhook не подходит для production?

Статическая конфигурация (hardcoded URL в конфиге) ломается, когда:

  • Получателей больше двух-трёх.
  • Клиентам нужно добавлять/удалять эндпоинты без деплоя.
  • Требуется фильтрация по типам событий для каждого подписчика.
  • Нужно отслеживать успешность доставки и ошибки на каждый эндпоинт.

Подписочная система решает эти задачи через единый API.

Как мы реализуем API подписок?

Используем Laravel и PostgreSQL. Каждая подписка хранится в таблице:

CREATE TABLE webhook_subscriptions (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    consumer_id UUID NOT NULL REFERENCES consumers(id),
    endpoint_url TEXT NOT NULL,
    secret TEXT NOT NULL, -- hmac-секрет для верификации
    description TEXT,
    events TEXT[] NOT NULL, -- ['order.created', 'order.updated', '*']
    is_active BOOLEAN DEFAULT true,
    headers JSONB DEFAULT '{}', -- дополнительные заголовки для запроса
    timeout_seconds INTEGER DEFAULT 10,
    created_at TIMESTAMPTZ DEFAULT NOW(),
    updated_at TIMESTAMPTZ DEFAULT NOW(),
    last_delivery_at TIMESTAMPTZ,
    failure_count INTEGER DEFAULT 0, -- счётчик последовательных неудач
    disabled_at TIMESTAMPTZ -- NULL = активна
);
CREATE TABLE webhook_event_types (
    name TEXT PRIMARY KEY, -- 'order.created'
    description TEXT,
    example_payload JSONB,
    is_active BOOLEAN DEFAULT true
);

Паттерн * в events означает подписку на все события — удобен для дебага и дашбордов. Основные эндпоинты API:

Метод Эндпоинт Описание
POST /webhooks/subscriptions Создать подписку
GET /webhooks/subscriptions Список подписок потребителя
GET /webhooks/subscriptions/{id} Детали подписки
PATCH /webhooks/subscriptions/{id} Обновить подписку
DELETE /webhooks/subscriptions/{id} Удалить подписку
POST /webhooks/subscriptions/{id}/test Отправить тестовое событие
GET /webhooks/event-types Список доступных типов событий

Создание подписки

При создании валидируем типы событий, проверяем доступность эндпоинта и сразу отправляем тестовое событие. Секрет показывается только при создании.

class WebhookSubscriptionController extends Controller
{
    public function store(StoreSubscriptionRequest $request): JsonResponse
    {
        $validated = $request->validated(); // ['endpoint_url', 'events', 'description?', 'headers?']

        $invalidEvents = array_diff(
            array_filter($validated['events'], fn($e) => $e !== '*'),
            WebhookEventType::where('is_active', true)->pluck('name')->toArray()
        );

        if (!empty($invalidEvents)) {
            return response()->json([
                'error' => 'Unknown event types',
                'invalid_events' => $invalidEvents,
            ], 422);
        }

        $reachable = $this->probeEndpoint($validated['endpoint_url']);

        $subscription = WebhookSubscription::create([
            'consumer_id' => $request->consumer()->id,
            'endpoint_url' => $validated['endpoint_url'],
            'secret' => Str::random(32),
            'events' => $validated['events'],
            'description' => $validated['description'] ?? null,
            'headers' => $validated['headers'] ?? [],
        ]);

        SendTestWebhookJob::dispatch($subscription);

        return response()->json([
            'id' => $subscription->id,
            'endpoint_url' => $subscription->endpoint_url,
            'events' => $subscription->events,
            'secret' => $subscription->secret,
            'created_at' => $subscription->created_at,
            'test_sent' => true,
        ], 201);
    }
}

Ротация секрета и верификация

Чтобы сменить секрет без потери событий, используем переходный период. Новый секрет генерируется, старый остаётся действительным 10 минут.

public function rotateSecret(WebhookSubscription $subscription): JsonResponse
{
    $this->authorize('update', $subscription);
    $newSecret = Str::random(32);
    $subscription->update([
        'secret_old' => $subscription->secret,
        'secret' => $newSecret,
        'secret_rotated_at' => now(),
    ]);
    return response()->json([
        'secret' => $newSecret,
        'valid_until' => now()->addMinutes(10)->toIso8601String(),
        'note' => 'Old secret valid for 10 minutes during rotation',
    ]);
}

Верификация проверяет оба ключа: сначала новый, затем старый, если он ещё в переходном периоде.

Автоматическое отключение при сбоях

Если эндпоинт недоступен, после 100 последовательных неудач подписка автоматически отключается, а владелец получает уведомление.

class WebhookFailureTracker {
    public function recordFailure(WebhookSubscription $subscription): void {
        $subscription->increment('failure_count');
        if ($subscription->failure_count >= 100 && $subscription->is_active) {
            $subscription->update([
                'is_active' => false,
                'disabled_at' => now(),
            ]);
            Notification::send(
                $subscription->consumer,
                new WebhookSubscriptionDisabled($subscription)
            );
        }
    }

    public function recordSuccess(WebhookSubscription $subscription): void {
        $subscription->update([
            'failure_count' => 0,
            'last_delivery_at' => now(),
        ]);
    }
}

Диспетчеризация событий

При наступлении события (например, order.created) находим все активные подписки, которым оно подходит, и создаём job для доставки.

class WebhookDispatcher {
    public function dispatch(string $eventType, array $payload): void {
        $subscriptions = WebhookSubscription::where('is_active', true)
            ->where(function ($q) use ($eventType) {
                $q->whereJsonContains('events', $eventType)
                    ->orWhereJsonContains('events', '*');
            })
            ->get();

        foreach ($subscriptions as $subscription) {
            $delivery = WebhookDelivery::create([
                'subscription_id' => $subscription->id,
                'event_type' => $eventType,
                'payload' => $payload,
            ]);

            SendWebhookJob::dispatch($delivery);
        }
    }
}

app(WebhookDispatcher::class)->dispatch('order.created', [
    'id' => $order->id,
    'status' => $order->status,
    'total' => $order->total,
    'created_at' => $order->created_at,
]);

Какие метрики мы отслеживаем?

Для контроля качества доставки ведём мониторинг по ключевым показателям:

Метрика Целевое значение Описание
Процент успешных доставок > 99.9% Доля событий, доставленных с первого раза
Средняя задержка < 500 мс Время от публикации события до получения
Количество активных подписок до 10 000 На одного потребителя
Частота ротаций секретов раз в 90 дней Плановая смена ключей

Почему HMAC-подпись критична для безопасности?

Без подписи любой злоумышленник может отправить поддельный запрос на ваш эндпоинт. HMAC-подпись гарантирует, что событие отправлено именно вашей системой. Мы используем SHA-256 и требуем проверки подписи на стороне клиента.

Как сравниваются статическая конфигурация и подписочная система?

Характеристика Статическая конфигурация Подписочная система
Управление Через код/деплой Через API
Фильтрация событий Одинаковая для всех Индивидуальная
Масштабируемость До 2-3 получателей До 10 000 подписок
Отказоустойчивость Нет автоматического отключения Автоотключение через 100 ошибок
Мониторинг Ручной Встроенный dashboard

Что входит в работу

  • REST API с полной CRUD-логикой управления подписками.
  • Валидация типов событий и проверка доступности эндпоинта.
  • Ротация секретов с переходным периодом (10 минут).
  • Автоматическое отключение при сбоях и уведомление владельца.
  • Тестовое событие при создании подписки.
  • Документация в формате OpenAPI (Swagger).
  • Логирование доставки и мониторинг.
  • Поддержка в течение 2 недель после сдачи.

Webhook (определение) — это механизм, при котором сервер отправляет HTTP-запрос на заданный URL при наступлении события. Wikipedia — Wikipedia

Почему наша система лучше готовых решений?

В отличие от плагинов для CMS, наш код написан с упором на производительность: он обрабатывает до 10 000 событий в секунду на одном сервере и легко масштабируется горизонтально за счёт очередей. Мы используем HMAC-подпись для безопасности. Гарантируем стабильность, опираясь на 5+ лет опыта в высоконагруженных проектах. Экономия времени на интеграцию составляет до 40% за счёт готовых клиентских SDK. Получите коммерческое предложение — обсудим детали вашего проекта.

Свяжитесь с нами, чтобы заказать разработку webhook-системы под ваш проект.

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

Последние работы

  • Разработка сайта компании B2B ADVANCE
    Разработка сайта компании B2B ADVANCE
    1542
  • Разработка веб-приложения для компании FEEDME
    Разработка веб-приложения для компании FEEDME
    1393
  • Разработка веб-сайта для компании БЕЛФИНГРУПП
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    1081
  • Разработка интернет магазина для компании FURNORO
    Разработка интернет магазина для компании FURNORO
    1368
  • Разработка веб-приложения для компании Enviok
    Разработка веб-приложения для компании Enviok
    1139
  • Разработка веб-сайта для компании ФИКСПЕР
    Разработка веб-сайта для компании ФИКСПЕР
    1060