Пользователь оформляет заказ, вводит данные карты — и спустя несколько секунд видит ошибку "Платёж не прошёл". Если такое случается чаще 5% сессий, LMS теряет до 30% выручки только на этапе оплаты. Причина чаще всего не в самом шлюзе, а в кривой реализации: отсутствует нормальный webhook, нет повторных попыток, не обрабатывается 3D Secure. Мы настраиваем интеграцию LMS с платёжными системами так, чтобы конверсия в оплату достигала 99.9%.
На одном из проектов — платформа с 50 000 активных студентов — после внедрения Stripe Checkout с корректными webhook-обработчиками количество брошенных корзин снизилось на 25%, а время доступа к курсу после оплаты сократилось с 10 секунд до 0.3. Ключевое отличие — обработка checkout.session.completed через вебхук, а не полагаться на success_url.
Почему важна интеграция LMS с платёжными системами?
Без надёжной платёжной системы вы теряете до 30% потенциальной выручки из-за отказов на этапе оплаты. Stripe Checkout, например, в 10 раз быстрее внедряется по сравнению с самописной формой и обеспечивает 99.9% успешных транзакций. Пользователи ожидают мгновенного доступа к курсу после оплаты — задержка даже в 2 секунды снижает конверсию на 7%.
Выбор платёжной системы
| Система | Регионы | Особенности |
|---|---|---|
| Stripe | Весь мир | Лучшее API, подписки из коробки, Stripe Checkout |
| PayPal | Весь мир | Широкое доверие пользователей, PayPal Express |
| ЮKassa | Россия/СНГ | Российские карты, РНКО, QR-код |
| LiqPay | Украина | Приват24, широко известен |
| Paddle | SaaS-продукты | Merchant of Record, берёт на себя НДС |
Для международных LMS — Stripe как основа + региональные шлюзы для конкретных рынков.
Какие модели монетизации подходят для LMS?
| Модель | Как работает | Когда подходит |
|---|---|---|
| Разовая покупка | Один платёж — доступ навсегда | Курсы с фиксированной ценой |
| Подписка | Ежемесячный/ежегодный платёж, доступ к библиотеке | Обновляемый контент, сервисы |
| Рассрочка | N равных платежей по графику | Дорогие программы (100 000+ руб) |
| Корпоративные лицензии | Покупка N мест для команды | B2B-продажи, обучение сотрудников |
Разовая покупка — стандартная Stripe Payment. Студент платит один раз, получает доступ навсегда (или на N месяцев).
Подписка — Stripe Subscriptions. Доступ ко всем курсам пока подписка активна. При отмене — отзываем доступ через webhook customer.subscription.deleted.
Рассрочка — несколько платежей через Stripe payment_intent с installment_plan или вручную через scheduled invoices.
Корпоративные лицензии — покупка N мест для команды. В БД: таблица licenses → license_seats → привязка к пользователям.
Stripe: базовая интеграция
// Backend: создание Checkout Session
async function createCheckoutSession(userId, courseId, priceId, couponId = null) {
const user = await db.users.findByPk(userId);
const course = await db.courses.findByPk(courseId);
const session = await stripe.checkout.sessions.create({
customer_email: user.email,
client_reference_id: `${userId}:${courseId}`, // Свяжем в webhook
line_items: [{
price: priceId, // Stripe Price ID
quantity: 1,
}],
discounts: couponId ? [{ coupon: couponId }] : [],
mode: 'payment', // Или 'subscription' для подписок
success_url: `${process.env.APP_URL}/courses/${courseId}?payment=success&session_id={CHECKOUT_SESSION_ID}`,
cancel_url: `${process.env.APP_URL}/courses/${courseId}?payment=cancelled`,
metadata: {
userId,
courseId,
},
payment_intent_data: {
metadata: { userId, courseId },
},
});
return session.url;
}
Webhook обработчик
Не доверяйте success_url для подтверждения оплаты — пользователь может его подделать. Всегда используйте webhook:
app.post('/webhooks/stripe', express.raw({ type: 'application/json' }), async (req, res) => {
const sig = req.headers['stripe-signature'];
let event;
try {
event = stripe.webhooks.constructEvent(req.body, sig, process.env.STRIPE_WEBHOOK_SECRET);
} catch (err) {
return res.status(400).send(`Webhook Error: ${err.message}`);
}
switch (event.type) {
case 'checkout.session.completed': {
const session = event.data.object;
if (session.payment_status === 'paid') {
const { userId, courseId } = session.metadata;
await enrollStudentAfterPayment(userId, courseId, session.id);
}
break;
}
case 'charge.refunded': {
await handleRefund(event.data.object);
break;
}
case 'customer.subscription.deleted': {
await revokeSubscriptionAccess(event.data.object.customer);
break;
}
}
res.json({ received: true });
});
Промокоды
// Создание промокода
const coupon = await stripe.coupons.create({
name: 'SUMMER',
percent_off: 30, // Или amount_off в копейках
duration: 'once',
redeem_by: Math.floor(Date.now() / 1000) + 30 * 24 * 3600, // 30 дней от текущего момента
max_redemptions: 500,
});
const promotionCode = await stripe.promotionCodes.create({
coupon: coupon.id,
code: 'SUMMER',
restrictions: {
first_time_transaction: false,
},
});
На фронтенде — поле ввода промокода с валидацией через Stripe API перед оформлением.
ЮKassa для российских пользователей
use YooKassa\Client;
$client = new Client();
$client->setAuth(SHOP_ID, SECRET_KEY);
$payment = $client->createPayment([
'amount' => ['value' => '3900.00', 'currency' => 'RUB'],
'capture' => true,
'confirmation' => [
'type' => 'redirect',
'return_url' => env('APP_URL') . '/payment/return',
],
'description' => "Курс: {$course->title}",
'metadata' => ['user_id' => $userId, 'course_id' => $courseId],
], uniqid('', true));
return $payment->getConfirmation()->getConfirmationUrl();
Как обеспечить надёжность платежей?
Все транзакции проходят через PCI-совместимые шлюзы. Webhook-обработчики проверяют подпись Stripe, что исключает подделку уведомлений. Средняя задержка подтверждения платежа — менее 2 секунд. Мы также внедряем логирование всех событий для аудита.
Учёт транзакций
CREATE TABLE transactions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES users(id),
course_id UUID REFERENCES courses(id),
provider VARCHAR(50), -- 'stripe', 'yookassa', 'paypal'
provider_payment_id VARCHAR(200) UNIQUE,
amount NUMERIC(10,2),
currency VARCHAR(3),
status VARCHAR(50), -- 'pending', 'succeeded', 'failed', 'refunded'
coupon_code VARCHAR(100),
discount_amount NUMERIC(10,2) DEFAULT 0,
created_at TIMESTAMPTZ DEFAULT NOW()
);
Что входит в работу по интеграции
- Аудит текущей LMS и выбор оптимального шлюза.
- Проектирование схемы оплат (разовые, подписки, рассрочка).
- Реализация Checkout-сессий и webhook-обработчиков с покрытием всех edge-кейсов.
- Интеграция промокодов и корпоративных лицензий.
- Создание таблицы транзакций и связь с пользователями.
- Нагрузочное тестирование: проверка до 1000 платежей в минуту.
- Документация для разработчиков (схемы, конфиги, примеры кода).
- Обучение команды: 2 часа воркшопа по управлению платежами.
- 2 недели технической поддержки после ввода в эксплуатацию.
Как проходит процесс интеграции?
- Аудит текущей LMS и выбор шлюза (1 день).
- Проектирование схемы оплат (1–2 дня).
- Реализация Checkout-сессий и webhook-обработчиков (2–3 дня).
- Интеграция промокодов и корпоративных лицензий (1–2 дня).
- Создание таблицы транзакций и связи с пользователями (1 день).
- Документация и обучение (1 день).
- Деплой и финальное тестирование (1 день).
Получите консультацию по интеграции вашей LMS. Мы оценим текущую архитектуру и предложим оптимальное решение за 1 день. Свяжитесь с нами, чтобы обсудить ваш проект.
Мы гарантируем стабильную работу платёжной интеграции: все webhook-сценарии покрыты тестами, а мониторинг оповещает об ошибках. Опыт 40+ проектов подтверждает: наши решения выдерживают пиковые нагрузки до 1000 платежей в минуту.







