I'm currently migrating my app from using the Stripe Charges API to use the Stripe PaymentIntents API, in order to comply with SCA regulations. My application is a subscription service with a recurring billing model, so I've been generally following the "Gym Membership" examples of the migration docs, as well as looking at other relevant docs and references.
I'm using Stripe Elements at the front-end to capture payment details etc. on a custom form and then send to my backend with Stripe payment token for further processing (synchronously). The frontend updates are simple enough and I have no problems there, but I'm a bit confused with the backend updates.
All the code examples I can find in the docs (which are usually terrific) show how to convert Charge
calls to PaymentIntent
calls e.g. this old Charge call:
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);
...becomes this using the 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);
So if additional authorization is required by the customer (as indicated by the PaymentIntent
status), the request will be kicked back to the customer and the Stripe SDK will handle the additional security measures.
But my app is not using Charge
calls in this way. It generally looks like this:
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 ??
Are the new Customer
creation, new PaymentSource
creation and new Subscription
creation calls subject to the SCA rejection, at which point I would have to return to the customer for further authentication?
If so, how do I check if this is necessary with the Customer and PaymentSource calls and how do I get the required client secret token to send back to the frontend? The Subscription object does provide access to a SetupIntent
object that has status and client secret, so do I have to check and use these?
Any links to relevant docs with examples would be very helpful.