使用循环计费模型更新 SCA 的 Stripe 付款

Updating Stripe payments for SCA with recurring billing model

我目前正在将我的应用从使用 Stripe Charges API 迁移到使用 Stripe PaymentIntents API,以符合 SCA 规定。我的应用程序是一个订阅服务,采用定期计费模式,因此我通常一直在关注迁移文档的 "Gym Membership" 示例,并查看其他相关文档和参考资料。

我在前端使用 Stripe Elements 在自定义表单上捕获付款详细信息等,然后使用 Stripe 付款令牌发送到我的后端以进行进一步处理(同步)。前端更新很简单,我在那里没有问题,但我对后端更新有点困惑。

我可以在文档中找到的所有代码示例(通常都很棒)展示了如何将 Charge 调用转换为 PaymentIntent 调用,例如这个旧的收费电话:

Map<String, Object> chargeParams = new HashMap<String, Object>();
chargeParams.put("amount", 1099);
chargeParams.put("currency", "eur");
chargeParams.put("source", request.token_id);
Charge.create(chargeParams);

...使用 PaymentIntents API:

Map<String, Object> createPaymentIntentParams = new HashMap<String, Object>();
createPaymentIntentParams.put("currency", "eur");
createPaymentIntentParams.put("amount", 1099);
createPaymentIntentParams.put("confirm", true);
createPaymentIntentParams.put("confirmation_method", "manual");
createPaymentIntentParams.put("payment_method", request.paymentMethodId);
intent = PaymentIntent.create(createPaymentIntentParams);

因此,如果客户需要额外授权(如 PaymentIntent 状态所示),请求将被踢回客户,Stripe SDK 将处理额外的安全措施。

但我的应用没有以这种方式使用 Charge 调用。它通常看起来像这样:

Map<String, Object> srchOpts = new HashMap<>();
srchOpts.put("email", userEmail);   

List<Customer> matchingCustomers = Customer.list(srchOpts).getData();
Customer customer = null;
Subscription subscription = null;

if ( matchingCustomers.isEmpty() ){
    Map<String, Object> params = new HashMap<String, Object>();
    params.put("email", userEmail);
    params.put("source", stripeToken);
    customer = Customer.create(params); // potential SCA rejection ??
}
else if (matchingCustomers.size() == 1) {
    customer = matchingCustomers.get(0);
    Map<String, Object> params = new HashMap<String, Object>();
    params.put("source", stripeToken);
    PaymentSourceCollection paymentSources = customer.getSources();
    paymentSources.create(params); // potential SCA rejection ??
}

Map<String, Object> item = new HashMap<String, Object>();
item.put("plan", planId);

Map<String, Object> items = new HashMap<String, Object>();
items.put("0", item);

Map<String, Object> params = new HashMap<String, Object>();
params.put("items", items);

params.put("customer", customer.getId());
subscription = Subscription.create(params); // potential SCA rejection ??

Customer 创建、新 PaymentSource 创建和新 Subscription 创建调用是否会受到 SCA 拒绝,此时我必须 return客户进一步验证?

如果是这样,我如何通过 Customer 和 PaymentSource 调用检查这是否有必要,以及如何获得所需的客户端秘密令牌以发送回前端? Subscription 对象确实提供对具有状态和客户端机密的 SetupIntent 对象的访问,所以我必须检查和使用这些吗?

任何带有示例的相关文档链接都将非常有帮助。

唯一需要 SCA 的时间是您尝试付款时。在您收集了客户的付款详细信息(并可选择将其保存为新客户)后,您要求 Stripe 完成付款。 Stripe 随后将联系客户的银行并询问是否可以付款或是否需要额外的身份验证。

如果银行说不需要额外的,支付成功,一切正常。

如果银行说需要 3DS 支票,那么您需要 运行 您的客户通过 3DS 流程,这实质上是一个 2FA 步骤,以确保请求付款的人也是持卡人.

如果您的客户仍然 "on-session"(例如,仍在您的网站上),您会将新创建的 PaymentIntent 客户端密码传递给您的前端并使用 Stripe.js 完成 2FA 步骤并进行身份验证付款。

如果您的客户是 "off-session"(例如,这是一个定期订阅并且他们不在您的网站上),那么您将必须通过电子邮件向您的客户发送电子邮件,让他们回到您的网站上以执行 3DS 步骤(或者你可以使用 Stripe 的 hosted invoice page).

在您的情况下,当您创建订阅时(假设您没有使用试用期),Stripe 将创建一个附有自动创建的 PaymentIntent 的发票。您可以通过 Subscription 上的 latest_invoice 参数访问此发票。如果需要 3DS 步骤,PaymentIntent 将具有 requires_action 状态,这意味着您需要让您的客户返回 "on-session" 才能完成付款。

在这种情况下,通过托管发票页面,Stripe 会自动向您的用户发送电子邮件,以便他们完成付款。如果没有托管发票页面,您将必须构建自己的实现才能让您的用户回来 "on-session"。

创建 Customer 或 PaymentMethod 时不需要执行 3DS,只有当您实际尝试将资金从一个地方转移到另一个地方时才需要。