Каждому платёжному webhook нужно три гарантии: authenticity (запрос правда от нас), at-least-once доставка (события не теряются молча) и idempotency (повторные доставки не дублируют запись в БД).
Authenticity: каждый webhook Baynoy несёт заголовок X-Baynoy-Signature — sha256(timestamp + '.' + body) с секретом вашего эндпоинта. Отвергайте, если timestamp старше 5 минут (защита от replay) или подпись не совпадает по constant-time. Мы следуем точно формату Stripe, существующее middleware верификации Stripe ставится без изменений.
At-least-once: ретраим с экспоненциальным backoff — 1м, 5м, 30м, 2ч, 12ч, 24ч — потолок шесть попыток. Каждая попытка пишет строку в baynoy_webhook_deliveries со статусом ответа. Кнопка replay-from-UI в дашборде идёт по тому же пайплайну.
Idempotency: каждое событие несёт event.id (UUIDv7 — сортируемый, монотонно растущий). Сохраняйте при первом приёме и отбрасывайте дубликаты на уровне БД unique constraint'ом. Мы передоставим. Constraint — ваша страховочная сеть.
Три строчки middleware — и у вас webhook handler, переживающий 6-часовой outage без единого потерянного уведомления.