Add-payments-fron-end » History » Version 9
Dmitry Vasilev, 11/21/2025 10:53 AM
| 1 | 1 | Dmitry Vasilev | # Инструкция фронтенд-разработчикам |
|---|---|---|---|
| 2 | |||
| 3 | Как создавать Payment Methods через Stripe для нашего приложения |
||
| 4 | 📌 Цель |
||
| 5 | |||
| 6 | Пассажир должен добавить свою карту, чтобы мы могли: |
||
| 7 | |||
| 8 | - безопасно сохранять карту (Stripe vault) |
||
| 9 | - автоматически списывать деньги после поездки (off-session) |
||
| 10 | - проводить SCA-подтверждение (3D-Secure) |
||
| 11 | |||
| 12 | Для этого используется SetupIntent + Stripe Elements. |
||
| 13 | 2 | Dmitry Vasilev | |
| 14 | 5 | Dmitry Vasilev | ### 1️⃣ Шаг 1. Запросить SetupIntent с бэкенда |
| 15 | 3 | Dmitry Vasilev | |
| 16 | 4 | Dmitry Vasilev | **Дергаем ручку "Create setup intent object" - POST /api/payments/setup_intents** |
| 17 | 2 | Dmitry Vasilev | |
| 18 | Получаем |
||
| 19 | |||
| 20 | ``` |
||
| 21 | { |
||
| 22 | "data": { |
||
| 23 | "id": "seti_1SUmTQK65qfXWkSiVIM19pAC", |
||
| 24 | "client_secret": "seti_1SUmTQK65qfXWkSiVIM19pAC_secret_TRfp4egUtC6WlqSvYDjYruElmCEFjez", |
||
| 25 | "payment_method_types": [ |
||
| 26 | "card" |
||
| 27 | ], |
||
| 28 | "account_id": "0cf6a16f-6492-4190-842b-f1563e7e3d7b", |
||
| 29 | "user_id": "5f0d292c-f3f7-4a2a-b129-a1d0761cfb12", |
||
| 30 | "stripe_account_id": null |
||
| 31 | }, |
||
| 32 | "status": true |
||
| 33 | } |
||
| 34 | ``` |
||
| 35 | |||
| 36 | client_secret нужен фронту, чтобы вызвать Stripe.confirmCardSetup(). |
||
| 37 | 6 | Dmitry Vasilev | |
| 38 | 8 | Dmitry Vasilev | --- |
| 39 | |||
| 40 | 7 | Dmitry Vasilev | ### 2️⃣ Шаг 2. Инициализация Stripe на фронте |
| 41 | |||
| 42 | ``` |
||
| 43 | 6 | Dmitry Vasilev | import { loadStripe } from '@stripe/stripe-js'; |
| 44 | |||
| 45 | 1 | Dmitry Vasilev | const stripe = await loadStripe(PUBLIC_STRIPE_KEY); |
| 46 | 7 | Dmitry Vasilev | ``` |
| 47 | 9 | Dmitry Vasilev | |
| 48 | --- |
||
| 49 | |||
| 50 | ### 3️⃣ Шаг 3. Создать Card Element и собрать данные карты |
||
| 51 | |||
| 52 | ``` |
||
| 53 | const elements = stripe.elements(); |
||
| 54 | const cardElement = elements.create('card'); |
||
| 55 | cardElement.mount('#card-element'); |
||
| 56 | ``` |
||
| 57 | |||
| 58 | --- |
||
| 59 | |||
| 60 | ### 4️⃣ Шаг 4. Подтвердить SetupIntent (3D-Secure + сохранение карты) |
||
| 61 | |||
| 62 | ``` |
||
| 63 | const { setupIntent, error } = await stripe.confirmCardSetup( |
||
| 64 | clientSecret, |
||
| 65 | { |
||
| 66 | payment_method: { |
||
| 67 | card: cardElement, |
||
| 68 | billing_details: { |
||
| 69 | name: userFullName, |
||
| 70 | }, |
||
| 71 | }, |
||
| 72 | } |
||
| 73 | ); |
||
| 74 | ``` |
||
| 75 | |||
| 76 | Если всё ok: |
||
| 77 | |||
| 78 | setupIntent.status === "succeeded" |
||
| 79 | **setupIntent.payment_method // <-- вот это нужно передать на бэкенд** |
||
| 80 | |||
| 81 | Если ошибка: |
||
| 82 | |||
| 83 | - insufficient authentication |
||
| 84 | - card declined |
||
| 85 | - 3DS failed |
||
| 86 | - Фронту нужно отобразить сообщение. |
||
| 87 | |||
| 88 | --- |
||
| 89 | |||
| 90 | ### 5️⃣ Шаг 5. Отправить payment_method на бэкенд |
||
| 91 | |||
| 92 | ``` |
||
| 93 | POST /api/payments/payment_methods |
||
| 94 | Content-Type: application/json |
||
| 95 | Authorization: Bearer <token> |
||
| 96 | |||
| 97 | { |
||
| 98 | "payment_method": "pm_123456789" |
||
| 99 | } |
||
| 100 | ``` |
||
| 101 | |||
| 102 | Бэкенд: |
||
| 103 | |||
| 104 | - привязывает payment_method к Customer |
||
| 105 | - сохраняет в базе |
||
| 106 | - теперь карта готова к off-session оплатам |