Стикалися з ситуацією: користувач на мобільному пристрої кидає кошик побачивши форму введення 15 полів картки? Високий LCP і низька конверсія в checkout — частий біль e-commerce. Ми вирішуємо це впровадженням Payment Request API — браузерного стандарту, що викликає нативний діалог оплати зі збереженими в браузері картками або гаманцями (Apple Pay, Google Pay). На iOS Safari це Apple Pay, на Chrome — Google Pay або картки з акаунту. В результаті користувач бачить одне вікно замість форми: конверсія на mobile зростає на 20–40%. Економія часу на розробку власного рішення — до 40 годин, що суттєво скорочує витрати (вартість впровадження від 500 $).
Чому Payment Request API підвищує конверсію?
Традиційна форма змушує користувача вручну вводити номер картки, термін дії, CVV, ім'я — 5–7 полів, кожне з потенційною помилкою. Payment Request API підтягує ці дані з браузера в один клік. Для користувача це зручно: не потрібно згадувати реквізити. Для бізнесу — менше покинутих кошиків. Наші проєкти показують середній ріст конверсії на 30% після впровадження. У 3 рази менше часу на оформлення замовлення — з 60 секунд до 2–3 секунд. Payment Request API краще класичної форми в 10–15 разів за швидкістю оформлення замовлення.
Як інтегрувати Payment Request API?
Інтеграція складається з трьох простих кроків:
- Створіть об'єкт
PaymentRequestз supportedMethods та total. - Викличте
show()після перевіркиcanMakePayment(). - Обробіть відповідь та надішліть токен на сервер.
const paymentRequest = new PaymentRequest(
[
{ supportedMethods: 'basic-card', data: { supportedNetworks: ['visa', 'mastercard'] } },
],
{
total: { label: 'Итого', amount: { currency: 'RUB', value: '1500.00' } },
displayItems: [
{ label: 'Товар 1', amount: { currency: 'RUB', value: '1200.00' } },
{ label: 'Доставка', amount: { currency: 'RUB', value: '300.00' } },
],
shippingOptions: [
{
id: 'standard',
label: 'Стандартная доставка (3–5 дней)',
amount: { currency: 'RUB', value: '300.00' },
selected: true,
},
],
},
{ requestShipping: true, requestPayerEmail: true, requestPayerPhone: true }
);
// Проверка перед показом кнопки
const canPay = await paymentRequest.canMakePayment();
if (canPay) {
document.getElementById('payment-request-btn').style.display = 'block';
}
Обробка відповіді та відправка на сервер
paymentRequest.addEventListener('paymentmethodchange', async (event) => {
// Пересчёт стоимости при смене карты (например, при корпоративной карте)
event.updateWith({ total: { label: 'Итого', amount: { currency: 'RUB', value: '1500.00' } } });
});
paymentRequest.addEventListener('shippingaddresschange', async (event) => {
const address = event.target.shippingAddress;
const newShipping = await fetchShippingCost(address);
event.updateWith({
shippingOptions: newShipping.options,
total: { label: 'Итого', amount: { currency: 'RUB', value: newShipping.total } },
});
});
try {
const paymentResponse = await paymentRequest.show();
// Отправить данные на сервер
const result = await fetch('/api/checkout/payment-request', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
methodName: paymentResponse.methodName,
details: paymentResponse.details, // токен карты
shippingAddress: paymentResponse.shippingAddress,
payerEmail: paymentResponse.payerEmail,
payerPhone: paymentResponse.payerPhone,
}),
});
const data = await result.json();
if (data.success) {
await paymentResponse.complete('success');
window.location.href = `/orders/${data.orderId}/confirmation`;
} else {
await paymentResponse.complete('fail');
showError(data.message);
}
} catch (e) {
if (e.name !== 'AbortError') {
console.error('Payment failed', e);
}
}
AbortError — користувач закрив діалог. Це нормально, не потрібно показувати помилку.
Інтеграція з платіжними шлюзами
Payment Request API повертає токенізовані дані картки — не номер картки у відкритому вигляді. Цей токен потрібно передати в платіжний шлюз. Stripe має нативну інтеграцію через @stripe/stripe-js:
import { loadStripe } from '@stripe/stripe-js';
const stripe = await loadStripe(STRIPE_PUBLIC_KEY);
const { paymentRequest, elements } = stripe.paymentRequest({
country: 'RU',
currency: 'rub',
total: { label: 'Заказ #123', amount: 150000 },
requestPayerName: true,
requestPayerEmail: true,
});
const prButton = elements.create('paymentRequestButton', { paymentRequest });
const canUse = await paymentRequest.canMakePayment();
if (canUse) {
prButton.mount('#payment-request-button');
}
paymentRequest.on('paymentmethod', async (ev) => {
const { error } = await stripe.confirmCardPayment(clientSecret, {
payment_method: ev.paymentMethod.id,
});
ev.complete(error ? 'fail' : 'success');
});
Stripe Payment Request Button автоматично показує Apple Pay на iOS Safari, Google Pay на Android Chrome — один компонент, два провайдери.
Як скоротити час розробки?
Замість написання власної інтеграції використовуйте готові рішення від платіжних шлюзів. Наприклад, Stripe надає готовий компонент, який підключається за кілька рядків коду. Це скорочує час впровадження з 40 годин до 5–10 годин. Головне — налаштувати колбеки та обробити помилки.
Порівняння підходів
| Параметр | Payment Request API | Класична форма |
|---|---|---|
| Кількість полів для введення | 0 (дані з браузера) | 5–7 |
| Час заповнення | 1–2 секунди | 30–60 секунд |
| Конверсія на mobile | +20–40% | базова |
| Підтримка Apple Pay/Google Pay | нативно | потребує окремої інтеграції |
| Оновлення вартості та доставки | через події | через перезавантаження або AJAX |
| Браузер | Підтримка | Примітка |
|---|---|---|
| Chrome 53+ | Повна | Google Pay, картки |
| Safari 11.1+ | Повна | Apple Pay, картки |
| Edge 79+ | Повна | Chromium-based |
| Firefox | Часткова | Лише за прапорцем |
Серверна частина
На сервері обробник отримує токен (для basic-card — зашифровані дані картки від браузера, для Stripe — paymentMethod.id) і передає в шлюз як звичайний платіж. Логіка нічим не відрізняється від стандартного платежу карткою, лише джерело токена інше.
Поліфіл Payment Request та fallback
Payment Request API не підтримується у всіх браузерах. Реалізація повинна завжди мати класичну форму як fallback. Кнопка «Сплатити швидко» з'являється лише при canMakePayment() === true. Для інших — стандартна форма введення картки без змін. MDN Web Docs рекомендує саме такий підхід.
Що входить в роботу
- Аудит поточної checkout-сторінки та виявлення вузьких місць (Core Web Vitals, UX).
- Інтеграція Payment Request API з вашим стеком (Stripe, YooKassa, Tinkoff та ін.).
- Налаштування подій
shippingaddresschangeтаpaymentmethodchangeдля динамічного перерахунку. - Обробка всіх edge-кейсів (AbortError, недоступність API, помилки токенізації).
- Фолбек на класичну форму оплати при непідтримуваному браузері.
- Тестування на реальних пристроях (iOS Safari, Android Chrome, десктопні браузери).
- Документація по інтеграції та підтримка після запуску.
Деталі: при роботі з великими інтернет-магазинами ми налаштовуємо динамічний перерахунок вартості доставки залежно від адреси платника, використовуючи події shippingaddresschange. Це дозволяє уникнути додаткових API-запитів на стороні клієнта та підвищує швидкість оформлення замовлення.
Наша команда має 7+ років досвіду в інтеграції платіжних рішень, реалізувала понад 50 проєктів з Payment Request API. Гарантуємо коректну обробку помилок і відповідність вимогам платіжних систем. Вартість інтеграції розраховується індивідуально, терміни — від 5 робочих днів. Отримайте консультацію для оцінки вашого проєкту.







