EMZETT.
Войти

Вебхуки Stripe: надёжная обработка платежей

Коротко: Stripe сообщает вашему серверу о платежах, подписках и возвратах вебхуком; вы проверяете подпись, отвечаете быстро, обрабатываете идемпотентно и не полагаетесь на страницу возврата клиента.

Подробнее: После платежа клиент возвращается на ваш сайт, но браузер может быть закрыт или соединение оборваться. Надёжно только сообщение сервера (вебхук) от Stripe: HTTP POST с событием (checkout.session.completed, invoice.paid, customer.subscription.deleted …).

Подробности

Процесс

  1. Создайте конечную точку (/api/stripe/webhook) и выберите события в Stripe (панель или CLI).
  2. Проверьте подпись с помощью секрета вебхука и необработанного тела запроса:
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, Идемпотентность, Платёжные сервисы для несовершеннолетних