且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Stripe v3 - SetupIntents 和订阅

更新时间:2023-12-02 22:35:52

感谢 Eduardo 的提问.

Thanks for the question, Eduardo.

有几种方法可以创建订阅,同时获得客户 SCA 身份验证和稍后对卡收费的许可.假设我们已经创建了一个 Stripe Customer 对象,并且他们的 ID 存储在 stripe_customer_id 中.根据您现在的流程,有几个步骤:

There are a couple ways to create a Subscription while gaining the Customers SCA authentication and permission to charge the card later. Assuming we already have a Stripe Customer object created and their ID is stored in stripe_customer_id. With the flow you have now there are a couple steps:

  1. 创建SetupIntent.请注意,如果您使用 usage: 'off_session' 和 Customer 创建它,它会在确认后附加生成的 PaymentMethod.

  1. Create the SetupIntent. Note that if you create it with usage: 'off_session' and the Customer it'll attach the resulting PaymentMethod when confirmed.

setup_intent = Stripe::SetupIntent.create({
  customer: stripe_customer_id,
  usage: 'off_session',
})

  • 收集付款详细信息并在客户端上使用其 client_secret 确认 SetupIntent,这会将 PaymentMethod 附加到客户.请注意,它会附加但不会默认设置为 invoice_settings.default_payment_method,因此您需要稍后进行单独的 API 调用以更新 Customer(请参阅步骤 3).

  • Collect payment details and confirm the SetupIntent using its client_secret on the client which will attach the PaymentMethod to the customer. Note that it will attach but will not be set as the invoice_settings.default_payment_method by default, so you'll need to make a separate API call later to update the Customer (see step 3).

     stripe.confirmCardSetup(
       '{{setup_intent.client_secret}}', 
       {
         payment_method: {
           card: cardElement,
         },
       }
     ).then(function(result) {
       // Handle result.error or result.setupIntent
     });
    

  • 更新Customer 并将其invoice_settings.default_payment_method 设置为成功确认的SetupIntent 上PaymentMethod 的ID.

  • Update the Customer and set its invoice_settings.default_payment_method equal to the ID of the PaymentMethod on the successfully confirmed 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 
      }
    })
    

  • 使用 off_session: true 创建 Subscription

    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) 进行订阅的第一笔付款.如果订阅是在客户离开之后创建的,并且技术上应该可行,那么这在技术上是可以的.

    This uses what's called a "Merchant Initiated Transaction" (MIT) for the Subscription's first payment. This is technically okay if the Subscription is created later after the Customer leaves and should technically work.

    如果在您创建 Subscription 时客户在您的网站/应用程序上,还有另一个流程更正确,不需要使用 SCA 的 MIT 豁免.订阅 没有试用的流程如下:

    If the customer is on your site/app when you create the Subscription, there's another flow that is a bit more correct and doesn't require using a MIT exemption for SCA. The flow is the following for a Subscription without a trial:

    1. 在客户端使用 createPaymentMethod 收集卡详细信息(无 SetupIntent)

    stripe.createPaymentMethod({
      type: 'card',
      card: cardElement,
    }).then(function(result) {
      //pass result to your server.
    })
    

  • 将这些卡的详细信息附加到 Customer

    Stripe::PaymentMethod.attach(
      "pm_xxx", {
        customer: stripe_customer_id
      }
    )
    

  • 更新Customerinvoice_settings.default_payment_method

    Stripe::Customer.update(
      stripe_customer_id,
      invoice_settings: {
        default_payment_method: @requested_source
      }
    )
    

  • 创建订阅(没有 off_session: true)

    subscription = Stripe::Subscription.create(
      customer: data['customerId'],
      items: [
        {
          price: 'price_H1NlVtpo6ubk0m'
        }
      ],
      expand: ['latest_invoice.payment_intent']
    )
    

  • 使用Subscriptionlatest_invoicepayment_intentclient_secret来收集支付细节并在客户端确认.

  • Use the Subscription's latest_invoice's payment_intent's client_secret to collect payment details and confirm on the client.

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

  • 从 SCA 的角度来看,第二个支付流程更正确,以获得授权以对该卡收费.此处的指南概述了第二种方法:https://stripe.com/docs/billing/订阅/固定价格

    This second payment flow is a bit more correct from an SCA standpoint for getting authorization to charge the card. The second approach is outlined in the guide here: https://stripe.com/docs/billing/subscriptions/fixed-price

    我们还有一个条纹示例,您可以在这里进行实验:https://github.com/stripe-samples/subscription-use-cases/tree/master/fixed-price-subscriptions

    We also have a Stripe Sample you can use to experiment here: https://github.com/stripe-samples/subscription-use-cases/tree/master/fixed-price-subscriptions