3 Mistakes I made with Stripe Subscriptions, Payment Intents, Payment Elements, and Meteor

3 Mistakes I made with Stripe Subscriptions, Payment Intents, Payment Elements, and Meteor

I spend a lot of time with the Stripe API, and I found the transition to Payment Elements, PaymentIntents, SetupIntents, and Subscriptions to be very difficult to grok (and I spent a lot of times building the integration incorrectly).

So I’m writing the post that I wish I had when I kicked off this project.

In this article, I’ll go over the 3 mistakes that I made while migrating an old Stripe Elements integration to Stripe Payment Elements and integrating Setup Intents and Payment Intents.

  • Mistake #1 - I tried to fight Stripe's architecture
  • Mistake #2 - Incorrectly choosing between Setup Intents vs Payment Intents
  • Mistake #3 - Causing duplicate payments by creating my own Payment Intents  

Mistake #1 - I tried to fight Stripe architecture

My application was collecting payments previous to implementing these concepts, so I figured it was easiest to try to get these new APIs to work with my existing code as much as possible.

I was very wrong.

In short summary, Join It had always been a 1-step process for facilitating purchases. Collect the payment information and you’re done!

But the introduction of Stripe Elements, Setup Intents, and Payment Intents disrupts this. Now, the payment element needs to be initiated with information that’s specific to the buyer. For example, to generate a Payment Intent, you need to have the cart finalized and pass that information to the server before you can send that information to Stripe in exchange for a Payment Intent.

Mistake #2 - Incorrectly choosing between Setup Intents vs Payment Intents

While the names of these two objects might be illustrative enough for most, they were initially very confusing to me. It wasn’t clear which one to use in which scenario - especially in my case where some of our purchases use Stripe Billing and some use Stripe Invoicing.

This was made worse because I was still in a mindset of how things used to work with Stripe Elements (instead of Stripe Payment Elements) and I was still making Mistake #1 by trying to fight Stripe’s architecture.

And to top it off, I thought that I found a work around to reconfiguring my entire purchase flow. Essentially, I resisted implementing multiple steps and finalizing the order by relying on Setup Intents where I should have been using Payment Intents.

When I tested this, it worked fine for me because I was testing on a US-based credit card.

However, when it was ‘Live’ and we had European customers using cards that required a form of Strong Customer Authentication … there was an issue. The customers expected to be prompted by their bank to confirm a purchase, but because we were only collecting the authorization to charge in the future (a “set up”) - the customers’ banks were asking them to confirm a purchase of $0.00.

So in this case, if you’re collecting a payment from the customer - it might seems like a Setup Intent would work (indeed, I was able to successfully charge the correct amounts after the Setup Intent was confirmed … but it caused issues in cases like Strong Customer Authentication).

So in the end, you should probably be using Payment Intents.

Mistake #3 - Causing duplicate payments by creating my own Payment Intents  

Once I conceded that I would have to re-write our checkout flow and add multiple steps, I started reading the documentation and implementing Payment Attempts (this was after my failed approach with Setup Intents, of course).

Everything seemed to be working fine, I set it up to:

  • Collect the Order information
  • Submit Order information and pass to server
  • Create a Payment Intent (making sure that it’ll allow for ‘off_session’ charges in the future) on the server and pass back to respective ‘client_secret’ up to the client
  • Use the ‘client_secret’ to then initiate the Stripe Payment elements and confirmPayment
  • Once confirmed, I would use the resulting payment_method to set up the respective Subscription or Invoice.

Sounds great, right? Wrong!

This approach led to 2 charges:

  • 1 charge that came as a result of the Payment Intent
  • 1 charge that came automatically as a result of the creation of the Subscription or Invoice

The solution to these duplicate charges was that I wasn’t supposed to create a Payment Intent directly. To solve this, I created the Subscriptions and Invoices directly, and then those automatically generated the Payment Intent (and respective client secret).

Note: In the case of create a Subscription, you can to create the Subscription, then retrieve the first Invoice to find the related payment_intent (and then retrieve this Payment Intent to fetch the client_secret). Seriously, if I’m still doing this wrong … please, someone tell me! 😅