Интеграция платёжной системы Stripe на сайт
Stripe — стандарт де-факто для международных платежей. Документация исчерпывающая, SDK покрывает все основные языки, Stripe CLI упрощает локальную разработку. Работает с картами Visa, Mastercard, Amex, Apple Pay, Google Pay, SEPA, iDEAL и десятками других методов в зависимости от региона.
Важно: с марта 2022 Stripe приостановил работу с российскими юридическими лицами. Интеграция актуальна для белорусских, казахстанских, европейских и международных бизнесов.
Установка и конфигурация
composer require stripe/stripe-php
// config/services.php
'stripe' => [
'key' => env('STRIPE_KEY'),
'secret' => env('STRIPE_SECRET'),
'webhook_secret' => env('STRIPE_WEBHOOK_SECRET'),
],
Ключи: pk_test_... / sk_test_... для тестирования, pk_live_... / sk_live_... для боевой среды.
Payment Intent — современный подход
Stripe рекомендует использовать Payment Intents API вместо устаревшего Charges API. Payment Intent описывает намерение принять платёж и управляет 3D Secure автоматически.
Сервер — создание Payment Intent:
\Stripe\Stripe::setApiKey(config('services.stripe.secret'));
$paymentIntent = \Stripe\PaymentIntent::create([
'amount' => 1500, // в наименьших единицах (центах, копейках)
'currency' => 'eur',
'metadata' => ['order_id' => $order->id],
'automatic_payment_methods' => ['enabled' => true],
]);
return response()->json([
'clientSecret' => $paymentIntent->client_secret,
]);
Клиент — Stripe Elements:
import { loadStripe } from '@stripe/stripe-js';
import { Elements, PaymentElement, useStripe, useElements } from '@stripe/react-stripe-js';
const stripePromise = loadStripe(import.meta.env.VITE_STRIPE_KEY);
function CheckoutForm({ clientSecret }: { clientSecret: string }) {
const stripe = useStripe();
const elements = useElements();
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!stripe || !elements) return;
const { error } = await stripe.confirmPayment({
elements,
confirmParams: {
return_url: `${window.location.origin}/payment/complete`,
},
});
if (error) {
console.error(error.message);
}
};
return (
<form onSubmit={handleSubmit}>
<PaymentElement />
<button type="submit">Оплатить</button>
</form>
);
}
export default function Payment({ clientSecret }: { clientSecret: string }) {
return (
<Elements stripe={stripePromise} options={{ clientSecret }}>
<CheckoutForm clientSecret={clientSecret} />
</Elements>
);
}
PaymentElement автоматически отображает подходящие методы оплаты в зависимости от местоположения покупателя и настроек Dashboard.
Webhook
Для локальной разработки: stripe listen --forward-to localhost:8000/webhook/stripe
public function handleWebhook(Request $request): Response
{
$payload = $request->getContent();
$sigHeader = $request->header('Stripe-Signature');
try {
$event = \Stripe\Webhook::constructEvent(
$payload,
$sigHeader,
config('services.stripe.webhook_secret')
);
} catch (\Stripe\Exception\SignatureVerificationException $e) {
return response('Invalid signature', 400);
}
match ($event->type) {
'payment_intent.succeeded' => $this->handleSuccess($event->data->object),
'payment_intent.payment_failed' => $this->handleFailed($event->data->object),
default => null,
};
return response('OK', 200);
}
private function handleSuccess(\Stripe\PaymentIntent $intent): void
{
$orderId = $intent->metadata->order_id;
Order::where('id', $orderId)->update([
'status' => 'paid',
'transaction_id' => $intent->id,
]);
}
Возвраты
\Stripe\Stripe::setApiKey(config('services.stripe.secret'));
$refund = \Stripe\Refund::create([
'payment_intent' => $paymentIntentId,
'amount' => 750, // частичный; убрать для полного
]);
Stripe CLI для разработки
# Установка
brew install stripe/stripe-cli/stripe
# Форвардинг вебхуков на локальный сервер
stripe listen --forward-to http://localhost:8000/webhook/stripe
# Отправка тестового события
stripe trigger payment_intent.succeeded
Тестовые карты: 4242424242424242 — успех, 4000000000009995 — недостаточно средств, 4000002760003184 — требует 3D Secure.
Checkout Session — альтернатива для простых случаев
Если не нужен кастомный UI, Stripe Checkout Session даёт готовую страницу оплаты:
$session = \Stripe\Checkout\Session::create([
'line_items' => [[
'price_data' => [
'currency' => 'eur',
'unit_amount' => 1500,
'product_data' => ['name' => 'Товар 1'],
],
'quantity' => 1,
]],
'mode' => 'payment',
'success_url' => 'https://example.com/success?session_id={CHECKOUT_SESSION_ID}',
'cancel_url' => 'https://example.com/cancel',
'metadata' => ['order_id' => $order->id],
]);
return redirect($session->url);
Активация Stripe-аккаунта занимает 1–2 дня для большинства юрисдикций. Для белорусских ИП и юрлиц — регистрация возможна через европейское представительство.







