I've tried three different Stripe support people to get a clear answer on this. No-one seems to know how to solve this. I want to sign up a customer for a recurring subscription using Stripe. When selecting a plan, a credit card form is shown. Customers input credit card info and click Pay and the subscription is created.
I've done this using Stripe.js and tokens by adding a bit of JavaScript to my client:
function pay() {
stripe.createToken(card).then(function (result) {
if (result.error) {
// Do something
} else {
var token = result.token.id;
$.post("/api/subscriptions/create?token=" + token, ...);
}
});
}
On the server I put the token on the customer (examples in C# but could be anything):
customerService.Update(customerId, new CustomerUpdateOptions
{
SourceToken = token,
});
and create a subscription:
var items = new List<SubscriptionItemOption> {
new SubscriptionItemOption {
PlanId = newPlanId,
},
};
var subscriptionCreateOptions = new SubscriptionCreateOptions
{
CustomerId = customerId,
Items = items,
};
Subscription subscription = stripe.Subscriptions.Create(subscriptionCreateOptions);
Everything works as expected so far. Stripe automatically create an invoice for the first payment and creates an automatic charge. It also generates an invoice for the next month that looks fine.
I should be happy now but I'm not. When testing the code above, it doesn't work for cards requiring 3D secure and similar extended authentication checks. In that case, I get an error from Stripe when creating the subscription, saying that the card isn't valid (I guess since we never completed 3D secure authentication).
From what I can understand from the Stripe documentation, showing 3D secure authentication dialog will require me to use either Checkout or Intents API. I don't want to use Checkout, but the Intents API looks like the right choice.
Using intents, I need to ask for an intent first:
var createOptions = new PaymentIntentCreateOptions {
Amount = 4900,
Currency = "usd",
PaymentMethodTypes = new List<string> { "card" }
};
paymentIntents.Create(createOptions);
This produces a client secret that I send back to my client. Rather than calling createToken
. On the client, I call the handleCardPayment
function, which shows the 3D secure modal in the case it is required:
stripe.handleCardPayment(
clientSecret, cardElement
).then(function(result) {
if (result.error) {
// Display error.message in your UI.
} else {
$.post("/api/subscriptions/create?...");
}
});
The issue here is that handleCardPayment
create a charge on the customer. I don't want that since I want to automatically invoice the customer each month.
Does anyone know if it is possible to show 3D secure (and similar) without using intents or at least without creating a charge? I've read similar questions, where people are recommending creating the charge, then creating a subscription with 1 month of trial. This doesn't have the effect that I want since that will create a charge the first month and an invoice with a charge the following months.
Basically, I just want the simplest possible solution that still shows the 3D secure dialog.