Developers March 23, 2020

How the heck do ya'all keep your payment logic organized?


I am currently working with Stripe, and while I am truly impressed by the quality of their API's and well thought out models, I'm having a hard time properly implementing this within my own architecture.

The main problem I do have is dealing with all the edge cases. I'm trying to condense the logic exposed by stripe into three handlers which I want to expose to my own front-end, which on a conceptual level are:

  1. setPaymentMethod
  2. setSubscription
  3. cancelSubscription

I for one am quite allergic to messy code, and currently the logic dealing with creating a new subscription is more like conditional spaghetti. How do you keep your payment logic organized, and maybe more importantly, well tested including all edge cases?

To what levels have you gone to ensure payments can go through successfully? Am I the only one here being paranoid that people will be turned away because they are unable to get a paid subscription?

  1. 2

    A Stripe micro service with the following routes

    POST /customers
    POST /subscriptions
    DELETE /subscriptions

    You likely want to include reCAPTCHA to prevent card testing & maybe want to listen for webhooks

    POST /recaptcha
    POST /webhooks/invoice/payment-succeeded

    1. 1

      What do you do with this information in your backend? Do you make a call to the Stripe API's every time you need some subscription related information? How do you deal with the situation when Strong Customer Authentication (SCA) is required (which I believe is mainly an issue in Europe)?

      1. 1

        Stripe has a number of backend SDKs that you can use within each route's logic. Auth should be decoupled from Stripe. Your visitor can create an account with you which provisions an account within your auth & then a new customer in Stripe. Your auth provider should be able to generate short lived JWTs that you can include in each request header to any of your micro services. You can then use your auth providers backend SDK (they should have one) to verify the JWT/request as legit & then safely interact with Stripe through their SDK.

      2. 1

        Yes, just make a call to the API's of your payment processor.

        I'm not a lawyer but I think SCA is handled by the payment processor. You don't have to worry about that.

        1. 1

          SCA would require customers to sign in with their bank when making a purchase. Stripe would automatically handle this by emailing the customer, but giving this is a break of their flow I prefer to include this in the payment process.

          Maybe you were thinking about PCI compliance.

          1. 2

            Oh man didn't think you were going so complex haha. I looked at:
            This gives you SCA compliance out of the box.

            Why make it complex when you're starting out? Can always optimize later when you're getting revenue.

            1. 2

              There you have a great point, but given I have it working it would be a waste to throw it away wouldn't it 😎

  2. 1

    Hi Corstian,

    If you're planning to sell software internationally it's probably better to go with a service like Paddle instead of Stripe. Stripe is only the payment processing, it does not help you with taxes like VAT/GST/Sales Tax, which many countries (or jurisdictions inside countries) impose on software sellers.

    You can ensure payments go through by working with the test environment that Stripe (or services like Paddle) offer. In that environment you can buy your own product as many times as you want without actually paying money. Once everything is live, you can do a real payment to make sure everything goes through correctly.

    I'm not sure how to help you with the logic problems you seem to have. Maybe you could be more specific. You deal with payments the same way as any other aspect of your app (e.g. authentication). With payments you will probably work more with webhooks, which is different from usual I guess.

  3. 1

    Decide on some business rules up front that will limit the edge cases you need to account for. For example, many sites don't offer refunds. If you cancel, your subscription just expires at the end of the current period instead of renewing. Now you don't have to deal with refunds.

    If you are mainly thinking through the backend components of dealing with Stripe, you may want to check this out: It's written for Ruby on Rails, but the concepts are laid out in a simple and clear manner.

    1. 1

      Thanks for the resource! Though it's offline now, I'm able to access it through the wayback machine.

      Seems useful! I can definitely relate to the introduction :)

  4. 1

    This is a great question. I haven’t actually implemented stripe in I plan to do that really soon. My first set of customers I just had them pay me via PayPal.

    I’m thinking it shouldn’t be too hard but this questions has me rethinking that. Perhaps you’re overthinking it? Do you have need for the code in multiple places in the UI? You could just write a react hook if you need it in multiple locations.

    I’m thinking I’ll just need it in one simple payment form. So a hook might be overkill. Will just have a nice container for the payments page and break up the components and functions into little pieces. Testing is easier when functions are broken up into digestible meaningful chunks.

    Once I actually implement it I’ll chime back in :)

    1. 1

      I'm looking forward to hearing about your experiences! The Stripe Elements API for React includes a context which can be used via hooks, hence this is in fact the least of my worries.

      The most difficult part IMHO is dealing with the server side of things, where various checks have to be done, depending on the situation. Creating a customer in Stripe, adding (tokenized) card details, choosing the subscription, and handling several edge cases such as a re-subscribe, failed (initial) payments, trial periods, and up and down grades.

      I have started writing a blogpost on the way I deal with payments, primarily to keep myself focused through all the details. Maybe it might help you through some details later on!

  5. 1

    Here's how I do it for my own code: (See the README)

    Am I the only one here being paranoid that people will be turned away because they are unable to get a paid subscription?

    Frankly they probably will, all you can do is hope they will reach out via Twitter or email informing you of it.

    What really confuses me about Stripe is the new Payment Intent API. Charges and subscriptions are easy enough but payment intents seem like a whole new beast.

    1. 2

      Interesting template! Few questions;

      • What's the reason you went with collecting credit card information (hence subjecting yourself to PCI compliance audits) instead of going with Stripe Elements?
      • Any specific reason you require a certain order of requests? (For example, the requirement to cancel an existing subscription before creating a new one)
      • Listing subscriptions for a customer will include cancelled subscriptions, right?

      Besides that the logic seems pretty familiar; lots of if statements. Also, I only use the payment intents as a side effect of creating a subscription, and accompanying charge.

      1. 1

        What's the reason you went with collecting credit card information (hence subjecting yourself to PCI compliance audits) instead of going with Stripe Elements?

        Honestly I don't have a good reason for this. It's just faster to get started and test the API. I'm going to change this later on to use Stripe elements.

        I only allow 1 subscription at a time because this is a template for a SaaS product that would allow a user to have for example the Basic Plan, Pro Plan or Pro Plus Plan but not multiple at the same time.

        1. 1

          In the error code you say the balance carries over when cancelling the subscription. How do you manage to prorate without modifying the existing subscription?

          On multiple subscriptions; I understand the design choice, but looking back I think my question is based too much on my own practice of running endpoints to get something done (setSubscription for example, which creates or updates a subscription) instead of having separate CRUD operations, when it makes sense. Again, thanks for sharing your template!