Вебхуки 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, Ідемпотентність, Платіжні сервіси для неповнолітніх