Как интегрировать Stripe в интернет-магазин
Практика3 минРедакция Innovialabs
Коротко
Для большинства магазинов проще всего Stripe Checkout — готовая страница оплаты; Payment Element нужен для оплаты внутри вашего дизайна, а статус заказа всегда меняется только по вебхуку.
Коротко: какой вариант выбрать
У Stripe три основных способа принять оплату. Выбор зависит от того, сколько контроля над интерфейсом вам нужно.
| Вариант | Что это | Когда подходит |
|---|---|---|
| Payment Links | Ссылка на оплату без кода | Несколько товаров, продажи через соцсети и мессенджеры |
| Checkout | Страница оплаты Stripe, создаётся через API | Большинство интернет-магазинов |
| Payment Element | Встраиваемая форма в вашем дизайне | Нужен полный контроль над UX оплаты |
Checkout — разумный старт: Stripe сам показывает подходящие методы оплаты, обрабатывает 3D Secure и локализацию. Payment Element даёт больше гибкости, но требует больше кода и тестов.
Важно: Stripe работает только для компаний, зарегистрированных в поддерживаемых странах. Проверьте это до начала разработки.
Как работает Checkout
- Покупатель нажимает «Оплатить».
- Ваш сервер создаёт Checkout Session с товарами, валютой и адресами возврата.
- Покупатель переходит на страницу Stripe и платит.
- Stripe отправляет вебхук
checkout.session.completed, и вы помечаете заказ оплаченным.
import Stripe from "stripe";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
const session = await stripe.checkout.sessions.create({
mode: "payment",
line_items: [{ price: "price_123", quantity: 1 }],
metadata: { orderId: "A-1042" },
success_url: "https://shop.example/thanks?session_id={CHECKOUT_SESSION_ID}",
cancel_url: "https://shop.example/cart",
});
// redirect the customer to session.url
Передавайте ID заказа в metadata — так вебхук будет однозначно связан с заказом.
Payment Element и PaymentIntent
При встроенной форме центральный объект — PaymentIntent. Он хранит сумму, валюту и статус платежа.
- Сервер создаёт PaymentIntent и отдаёт фронтенду
client_secret. - Фронтенд монтирует Payment Element и вызывает подтверждение оплаты.
- Если банк требует 3D Secure, Stripe сам покажет проверку.
- Итоговый статус приходит вебхуком
payment_intent.succeededилиpayment_intent.payment_failed.
Сумму всегда считайте на сервере по данным заказа, а не берите с фронтенда.
Вебхуки: единственный источник правды
Страница «Спасибо» — не доказательство оплаты: пользователь может закрыть вкладку раньше. Заказ меняет статус только по вебхуку.
const event = stripe.webhooks.constructEvent(
rawBody, // raw request body, not parsed JSON
req.headers["stripe-signature"],
process.env.STRIPE_WEBHOOK_SECRET!
);
if (event.type === "checkout.session.completed") {
// mark order as paid if not already
}
Правила:
- проверяйте подпись по сырому телу запроса;
- обрабатывайте события идемпотентно — Stripe может прислать одно событие повторно;
- быстро отвечайте
2xx, тяжёлую работу выносите в очередь; - храните ID обработанных событий.
Возвраты
Возврат создаётся через API или в Dashboard по PaymentIntent. Возможен полный или частичный. Слушайте событие о возврате и обновляйте заказ: «возвращён» или «частично возвращён». Учтите, что деньги возвращаются покупателю не мгновенно — сроки зависят от банка.
Тестовый режим
- Используйте тестовые ключи — они полностью изолированы от боевых.
- Тестовая карта
4242 4242 4242 4242с любой будущей датой и любым CVC даёт успешную оплату; в документации есть карты для отказов и 3D Secure. - Stripe CLI пересылает вебхуки на локальный сервер:
stripe listen --forward-to localhost:3000/api/stripe/webhook. - Перед запуском проверьте: успешная оплата, отказ, 3D Secure, повторный вебхук, возврат.
Частые ошибки
- Статус заказа меняется по редиректу на success-страницу.
- Тело запроса парсится в JSON до проверки подписи — подпись не сходится.
- Сумма приходит с фронтенда и её можно подменить.
- Тестовые и боевые ключи перепутаны в окружениях.