Stripe v3 - SetupIntents и подписки

Я пытаюсь использовать SetupIntents для проверки и сохранения метода оплаты, а затем создать подписку, используя ее, чтобы взимать с клиента (сразу, а затем ежемесячно) требуемую сумму.

Кажется, это работает нормально:

  • Карта проверена (включая SCA при необходимости)
  • Способ оплаты создан, по умолчанию привязан к клиенту и включен для использования в будущем со статусом ВСТРЕЧЕН.
  • Подписка создана и использует указанный выше способ оплаты.

Проблема в том, что Stripe затем генерирует соответствующий счет-фактуру и платежное намерение, но последнее со статусом "requires_action" всякий раз, когда предоставленная карта требует безопасной авторизации клиента (SCA), даже если используется правильный способ оплаты (включен для использования в будущем) и проверка карты уже проведена.

Я думал, что весь смысл использования SetupIntents как раз в том, чтобы заранее проверить метод оплаты и иметь возможность взимать плату с клиента впоследствии.

Мое предположение просто неверно или это действительно возможно, и я просто что-то упускаю?

заранее спасибо

РЕДАКТИРОВАТЬ: это код создания подписки в бэкэнде:

# Set the default payment method on the customer
      Stripe::Customer.update(
        stripe_customer_id,
        invoice_settings: {
          default_payment_method: @requested_source
        }
      )

subscription = Stripe::Subscription.create({
       "customer" => stripe_customer_id,
       "proration_behavior" => 'create_prorations',
       "items" => [
         [
           "plan" => "#{@stripe_plan_api_id}",
         ],
       ],
       'default_tax_rates' => [
         "#{@stripe_tax_rate_id}",
       ],
       "expand" => ["latest_invoice.payment_intent"]
     });

1 ответ

Решение

Спасибо за вопрос, Эдуардо.

Есть несколько способов создать Subscriptionпри получении аутентификации клиента SCA и разрешения на списание средств с карты позже. Предполагая, что у нас уже есть объект Stripe Customer, и его идентификатор хранится вstripe_customer_id. Теперь у вас есть пара шагов:

  1. Создать SetupIntent. Обратите внимание, что если вы создадите его с использованием: 'off_session' иCustomer после подтверждения он прикрепит полученный метод PaymentMethod.

    setup_intent = Stripe::SetupIntent.create({
      customer: stripe_customer_id,
      usage: 'off_session',
    })
    
  2. Соберите платежные реквизиты и подтвердите SetupIntent, используя его client_secretна клиенте, который прикрепит к нему PaymentMethod. Обратите внимание, что он будет прикреплен, но не будет установлен какinvoice_settings.default_payment_method по умолчанию, поэтому вам нужно будет сделать отдельный вызов API позже, чтобы обновить Customer (см. шаг 3).

     stripe.confirmCardSetup(
       '{{setup_intent.client_secret}}', 
       {
         payment_method: {
           card: cardElement,
         },
       }
     ).then(function(result) {
       // Handle result.error or result.setupIntent
     });
    
  3. Обновите Customer и установить его invoice_settings.default_payment_method равный ID PaymentMethod на успешно подтвержденном SetupIntent.

    Stripe::Customer.update(
      stripe_customer_id, {
      invoice_settings: {
        default_payment_method: 'pm_xxxx', # passed to server from client. On the client this is available on the result of confirmCardSetup 
      }
    })
    
  4. Создать Subscription с участием off_session: true

    subscription = Stripe::Subscription.create({
      customer: stripe_customer_id,
      proration_behavior: 'create_prorations',
      items: [{
        plan: "#{@stripe_plan_api_id}",
      }],
      default_tax_rates: [
        "#{@stripe_tax_rate_id}",
      ],
      expand: ["latest_invoice.payment_intent"],
      off_session: true,
    })
    

При этом используется так называемая "транзакция, инициированная продавцом" (MIT) для первого платежа по подписке. Технически это нормально, если Подписка создается позже, после ухода Клиента, и технически должна работать.

Если клиент находится на вашем сайте / в приложении, когда вы создаете Subscription, есть другой поток, который немного более правильный и не требует использования исключения MIT для SCA. Поток для aSubscription без суда:

  1. Собирайте данные карты с помощью createPaymentMethod на клиенте (нет SetupIntent)

    stripe.createPaymentMethod({
      type: 'card',
      card: cardElement,
    }).then(function(result) {
      //pass result to your server.
    })
    
  2. Прикрепите данные карты к Customer

    Stripe::PaymentMethod.attach(
      "pm_xxx", {
        customer: stripe_customer_id
      }
    )
    
  3. Обновите Customerс invoice_settings.default_payment_method

    Stripe::Customer.update(
      stripe_customer_id,
      invoice_settings: {
        default_payment_method: @requested_source
      }
    )
    
  4. Создать Subscription(без off_session: true)

    subscription = Stripe::Subscription.create(
      customer: data['customerId'],
      items: [
        {
          price: 'price_H1NlVtpo6ubk0m'
        }
      ],
      expand: ['latest_invoice.payment_intent']
    )
    
  5. Использовать Subscriptionс latest_invoiceс payment_intentс client_secret для сбора реквизитов платежа и подтверждения на клиенте.

    stripe.confirmCardPayment(
      '{{subscription.latest_invoice.payment_intent.client_secret}}', { ......
    

Этот второй поток платежей немного более правильный с точки зрения SCA для получения авторизации для списания средств с карты. Второй подход описан в руководстве здесь: https://stripe.com/docs/billing/subscriptions/fixed-price.

У нас также есть образец полосы, который вы можете использовать для экспериментов здесь: https://github.com/stripe-samples/subscription-use-cases/tree/master/fixed-price-subscriptions

Другие вопросы по тегам