Payment Request API: הגדלת המרות במובייל עם תשלום מקורי
ראיתם משתמשים נוטשים את העגלה במובייל כשהם נתקלים בטופס עם 15 שדות לכרטיס אשראי? LCP גבוה והמרות נמוכות בקופה הם כאבים נפוצים במסחר אלקטרוני. אנחנו פותרים זאת על ידי הטמעת Payment Request API—תקן דפדפן שמפעיל דיאלוג תשלום מקורי באמצעות כרטיסים שמורים, Apple Pay או Google Pay. ב-iOS Safari זה Apple Pay; ב-Chrome זה Google Pay או כרטיסים מהחשבון. התוצאה: דיאלוג אחד במקום טופס. ההמרות במובייל עולות ב-20–40%. חיסכון של עד 40 שעות פיתוח מפחית משמעותית את עלות ההטמעה.
למה Payment Request API משפר המרות
טפסים מסורתיים מאלצים משתמשים להזין ידנית מספר כרטיס, תוקף, CVV, שם—5–7 שדות, כל אחד מועד לשגיאות. Payment Request API שולף נתונים אלה מהדפדפן בלחיצה אחת. למשתמשים זה נוח—אין צורך לזכור פרטים. לעסקים—פחות עגלות נטושות. בפרויקטים שלנו, אנו רואים עלייה ממוצעת של 30% בהמרות לאחר ההטמעה. זמן הקופה יורד מ-60 שניות ל-2–3 שניות—פי 30 מהר יותר.
איך אנו מטמיעים Payment Request API
הטמעה בסיסית כוללת שלושה שלבים: יצירת אובייקט PaymentRequest עם 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); } } לפני הצגת הכפתור—אחרת הוא יופיע למשתמשים שהדפדפן שלהם לא תומך ב-API.
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 מציג אוטומטית Apple Pay ב-iOS Safari ו-Google Pay ב-Android Chrome—רכיב אחד, שני ספקים.
איך אנו מקצרים את זמן הפיתוח
במקום לכתוב אינטגרציה מותאמת אישית, אנו משתמשים בפתרונות מוכנים משערי תשלום. Stripe מספק רכיב מובנה שמתחבר עם כמה שורות קוד. זה מקצר את זמן ההטמעה מ-40 שעות ל-5–10 שעות. המפתח הוא הגדרת callbacks נכונה וטיפול בשגיאות.
השוואת גישות
| פרמטר | Payment Request API | טופס קלאסי |
|---|---|---|
| שדות למילוי | 0 (נתונים מהדפדפן) | 5–7 |
| זמן מילוי | 1–2 שניות | 30–60 שניות |
| המרות במובייל | +20–40% | קו בסיס |
| תמיכה ב-Apple Pay/Google Pay | מקורי | דורש אינטגרציה נפרדת |
| עדכון מחיר ומשלוח | באמצעות אירועים | רענון עמוד או AJAX |
| דפדפן | תמיכה | הערות |
|---|---|---|
| Chrome 53+ | מלאה | Google Pay, כרטיסים |
| Safari 11.1+ | מלאה | Apple Pay, כרטיסים |
| Edge 79+ | מלאה | מבוסס Chromium |
| Firefox | חלקית | רק מאחורי דגל |
טיפול בצד השרת
בשרת, ה-handler מקבל את הטוקן (עבור 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—paymentMethod.id) ושולח אותו לשער כמו תשלום כרטיס רגיל. הלוגיקה זהה לעסקת כרטיס רגילה, רק מקור הטוקן שונה.
Polyfill וגיבוי
Payment Request API אינו נתמך בכל מקום. כל הטמעה חייבת לכלול טופס קלאסי כגיבוי. כפתור התשלום המהיר מופיע רק כאשר canMakePayment() === true. עבור כל השאר, טופס הזנת הכרטיס הסטנדרטי נשאר ללא שינוי. MDN Web Docs ממליץ על גישה זו.
מה כלול בעבודה שלנו
- ביקורת של דף הקופה הנוכחי שלכם לזיהוי צווארי בקבוק (Core Web Vitals, UX).
- אינטגרציה של Payment Request API עם המחסנית שלכם (Stripe, YooKassa, Tinkoff וכו').
- הגדרת אירועי
shippingaddresschangeו-paymentmethodchangeלחישוב דינמי מחדש. - טיפול בכל מקרי הקצה (AbortError, חוסר זמינות API, שגיאות טוקניזציה).
- גיבוי לטופס תשלום קלאסי לדפדפנים לא נתמכים.
- בדיקות על מכשירים אמיתיים (iOS Safari, Android Chrome, דפדפני דסקטופ).
- תיעוד ותמיכה לאחר השקה.
מקרה בוחן אמיתי
עבור לקוח עם 10,000 הזמנות חודשיות, הטמענו Payment Request API בקופה הניידת שלהם. לפני: זמן קופה ממוצע 45 שניות, המרות במובייל 2.1%. אחרי: זמן הקופה ירד ל-3 שניות, ההמרות במובייל עלו ל-2.8% (עלייה של 33%). ההטמעה ארכה 8 שעות באמצעות רכיבי Stripe, כולל טיפול בגיבוי ובדיקות על 20 שילובי מכשיר-דפדפן.
לצוות שלנו יש ניסיון של 10+ שנים באינטגרציות תשלום והוא השלים מעל 50 פרויקטים של Payment Request API. אנו מבטיחים טיפול נכון בשגיאות ועמידה בדרישות מערכות התשלום. עלות האינטגרציה נקבעת באופן אישי; לוח הזמנים מתחיל מ-5 ימי עסקים. צרו קשר להערכת פרויקט.







