Вебхуки Stripe: надёжная обработка платежей
Коротко: Stripe сообщает вашему серверу о платежах, подписках и возвратах вебхуком; вы проверяете подпись, отвечаете быстро, обрабатываете идемпотентно и не полагаетесь на страницу возврата клиента.
Подробнее: После платежа клиент возвращается на ваш сайт, но браузер может быть закрыт или соединение оборваться. Надёжно только сообщение сервера (вебхук) от Stripe: HTTP POST с событием (checkout.session.completed, invoice.paid, customer.subscription.deleted …).
Подробности
Процесс
- Создайте конечную точку (
/api/stripe/webhook) и выберите события в Stripe (панель или CLI). - Проверьте подпись с помощью секрета вебхука и необработанного тела запроса:
const sig = req.headers.get("stripe-signature")!;
const body = await req.text(); // сырое, не разобранное как JSON!
const event = stripe.webhooks.constructEvent(body, sig, process.env.STRIPE_WEBHOOK_SECRET!);Без проверки любой мог бы сообщать поддельные платежи. 3. Обработайте событие (пометить заказ оплаченным, задать статус подписки, отправить счёт). 4. Быстро ответьте 2xx; долгую работу вынесите в очередь/фоновое задание.
Надёжность
- Повторы: Stripe отправляет заново, если вы не ответили 2xx (в течение нескольких дней). Ваш код должен быть идемпотентным: сохраняйте идентификатор события (
event.id) и игнорируйте дубликаты; проверяйте переходы состояний. - Порядок не гарантирован: события могут прийти в другом порядке; при необходимости запросите объект у Stripe заново.
- Сбой базы данных: тогда отвечайте 5xx, чтобы Stripe повторил, а не потерял события. С бессерверными базами данных, которые сначала просыпаются, оставьте достаточный тайм-аут.
- Тестовый/боевой режим имеют раздельные секреты и конечные точки.
- Stripe CLI (
stripe listen --forward-to localhost:3000/api/stripe/webhook) для локального теста.
Безопасность и право
Храните секрет в тайне, только HTTPS, только необходимые события. Проверяйте сумму и валюту на сервере, не берите их из браузера. Персональные данные храните экономно (данные карт хранит Stripe, а не вы: нагрузка PCI низкая с Checkout/Elements). Право: уведомление об отказе, счета, условия, информация о цене, кнопка отмены для подписок, несовершеннолетние и договоры (согласие родителей). Это не юридическая консультация.
Типичные ошибки
- Тело заранее разобрано как JSON → проверка подписи не проходит.
- Неверный секрет (тестовый и боевой, несколько конечных точек).
- Нет идемпотентности: двойные зачисления/письма.
- Слишком медленный ответ → лавина повторов.
- Доверие только перенаправлению.
- События не журналируются: с журналом событий (
stripe_events) ошибки можно проследить позже. Следите за неудачными доставками в панели.
См. также: Stripe, Вебхуки, HMAC, Идемпотентность, Платёжные сервисы для несовершеннолетних