Issue #45 new

Support for Stripe Subscriptions

Jeffrey Olmstead
created an issue

I am in need of support for Stripe Subscriptions. This likely means I will be building it but before spending time on it was wondering if anyone had already started down this road. Info on Subscriptions can be found here: https://stripe.com/docs/api#subscriptions

Does Nwazet.Commerce currently support this? Any desire to or should I build this into my Rework.CommerceExtensions module?

Comments (9)

  1. Bertrand Le Roy repo owner

    Well, it's not in, so please go ahead. It will be an interesting addition, but if it's going to go into the main module, I'd like to do a spec review before, if that's ok.

  2. Jeffrey Olmstead reporter

    I have thought about this a lot today and it seems there are two approaches:

    • We integrate fully with Stripe (and any other payment gateway that comes up in the future) and have Stripe handle the subscription payments
      1. This is a heavy integration with Stripe and it is proving to be difficult to work within the Nwazet.Commere framework as there is so much to think about with different features being enabled
        1. What happens if someone applies a discount as Stripe doesn't allow our own discount on an item, needs to be a Stripe Discount
        2. How do we handle this in the shopping cart when some items are discount and others are regular items
        3. We currently don't have stripe store the contact / credit card token anywhere so it would not be feasible for a user to return to edit their subscription (without building it out)
      2. Under this model, would need a Stripe Customer module, a Stripe Credit Card module, and a Stripe Subscription module (which would expose a Subscription part to be attached wherever the Product part is used)
    • An approach I just thought of later today was to just abandon having Stripe automatically charge the card and have Orchard tasks submit the payment request on the time period desired (i.e. monthly / weekly / yearly)
      1. This puts the logic control back inside Orchard (which can be good) and makes it more adaptable to other payment providers
        1. Under this approach, the discounts / and subscription are handled by Orchard and the postings / cancelations are handled directly in Orchard
          • This means we would not need to handle setting up special subscription plans in Stripe and the amounts could be more fluid (say if you wanted to give one customer a price discount, you just type it in - Stripe would have you making a separate subscription or a discount item for that case as they don't allow for one off scenarios)
          • This means we would not need web hooks coming from Stripe (or any other payment providers) on cancelations or things changing on payment provider, events can be triggered right in Orchard
          • I don't think this would work well with PayPal though as they don't provide a token (for the credit card) to charge payments against but for Stripe it seems it can work
      2. I feel this approach would open door for better integration with other modules that could be developed (like a CRM) since the contact information / address / email is stored separate of the payment gateway
      3. Under this model, would still need a Customer module, a Stripe Credit Card module (wish it didn't have to be "Stripe" - possibly could be generic), and a Subscription module (which would expose a Subscription part to be attached wherever the Product part is used) but the logic would not be writing it back to Stripe, just holding it for posting of Stripe payments
        • Other nuances under this model are partial month handling or how to handle it if an Orchard Workflow fails (Stripe has built in retries)

    I hope I have explained my thoughts well on the above two approaches as I really would like some "outside" feedback on what would seem to be the best long term solution. I love the idea of having Stripe handle it though it could end up being restrictive over time / limiting payment gateways. Look forward to your thoughts.

  3. Bertrand Le Roy repo owner

    Yes, I'd like us to remain neutral with regards to the payment gateway for anything else than the actual payment: common features can then be abstracted, and re-used. Because of the recurring nature of subscriptions, we will have to create a Stripe customer, but on the Orchard side we can make that fairly generic. It will definitely be a tricky one to implement, but I hope extremely powerful. I like the possibilities it opens of integration with CRM, reporting, etc.

  4. Jeffrey Olmstead reporter

    Here are some of the items I see as being needed to make a recurring payment work (with Stripe / other payment providers)

    • A checkbox indicator on a product that it is a recurring payment
      • If checked, it would expose a time period indicator of daily, weekly, monthly, or yearly
      • Side note, not sure how to handle scenarios where a different payment provider is not set up to handle the recurring payment
    • If a product with a recurring payment is included in the shopping cart, then create a Stripe customer at the same time as the payment
      • This means Stripe will provide you back a Customer Id to be utilized for future charges
    • At checkout, store the user email address, Orchard UserId if they are logged in, product id that was recurring, product description, recurring amount, date of first charge, date of last successful charge, date of last failed charge, and Stripe CustomerId in a new database table for future charges to be made
    • Orchard Stripe Recurring Charge task would run every day to:
      • Determine what recurring charges will occur in the next XX days (triggers a workflow event - allows user to set up their own notification of upcoming payment template if they like)
      • Apply the recurring charges needed for the current day
        • If successful, trigger a success workflow event - allows user to set up their own receipt template if they like (or anything else)
        • If fails, trigger a failure workflow event - allows user to set up a "update credit card" template if they like (or anything else)
      • Try again to apply recurring charges that failed XX days ago (trigger same workflows as above)
        • Goal here is that the user would have updated their card information or canceled their subscription
    • Other views we would need are
      • Form to cancel subscription
      • Form to change address / credit card information
      • Form to make a single payment against recurring balance (i.e. to get caught up or ahead)
      • For all of these forms, while they assume a logged in user, because we are recording email address even when no UserId is available, it opens up the door to send a unique link to the email address on record for the non-authenticated user to make modifications
    • Other reports we would need are:
      • Report for user to see past payments and current balance
      • Report for user to see list of current subscriptions / recurring payments

    Those are my design thoughts. Love to get feedback before implementing it.

  5. Bertrand Le Roy repo owner

    Looks good. Make sure to inform the customer where their credit card information is going to be stored, with all the relevant links.

    Another possible feature could be the possibility to put a subscription on hold. Not sure how important that is, so it could be done later.

    Questions: do we have separate Nwazet.Subscriptions feature, with the Stripe module being enhanced to expose the relevant interfaces? Or do we also have a new, separate Stripe.Subscriptions feature?

    How would you implement discounts based on how long a user has been a subscriber?

  6. Jeffrey Olmstead reporter

    Good point on open exposure of storage. Would want to let the user know information is stored with Stripe.

    Yes, putting subscription on hold would be good to be supported by the interface, definitely see a user for that, whether a customer manually does it or a payment is overdue so the system automatically puts subscription on hold (rather than just terminating it).

    I feel like we should have a separate Nwazet.Subscriptions feature (keep this as generic as possible). Actually, I would like to also have a separate Nwazet.Checkout feature which removes the checkout steps from the Stripe feature. It would walk you through the steps of checkout (i.e. collecting address, name, reviewing order, etc) without the dependency on Stripe (keep stripe or any other payment gateway as a feature for clearing the payment right at the end, after the user selects the payment method they desire). This new feature could also handle Address changes, credit card updates, etc with the payment providers script / api call being injected based on available payment providers / what payment provider the user chose to update.

    This would make the Stripe feature mainly a feature that exposes all of the options presented in the Stripe API in a C# / javascript way. I don't know if that is feasible or if you desire it, but that would seem the most flexible should we want to drop in other payment providers. It would also provide a consistent checkout / card management experience, only the scripts on the page are provider specific.

    There are some Stripe C# libraries out there which may save time in boosting the available features in the Stripe module. However, most are under apache license (which I don't believe we would want to incorporate into this project due to licensing issues) and the rest seem to be privately licensed. Here is an example of what I mean that is "out there" https://github.com/ServiceStack/Stripe/blob/master/src/Stripe/StripeGateway.cs but would not be licensed for us to utilize.

    I am not yet sure on discounts, however, because of the fact that this is Orchard centric (i.e. charging every time period by Orchard, not by Stripe) we can have the amount change over time (i.e. discount) without a lot of labor in updating Stripe, just update the new table above with the new charge amount. However, the best solution is to expand our Promotions / Discount modules to have discounts that apply over time. Once we make it there, that will just be fun :)

    Look forward to your thoughts, especially about Nwazet.Checkout module.

  7. Bertrand Le Roy repo owner

    I have another question: how are the screens to change information protected? Are we requiring users to be authenticated Orchard users before they can buy a subscription? If so, how do we integrate user creation to the flow?

    I kept checkout in Stripe because the data required by payment gateways may be different. Not sure how you'd handle such differences. There may be commonalities, but I'd rather review this as a different feature/change set.

    Apache is not an issue, as it's compatible with the license used here. The real reason why I did not integrate one of the existing libraries is that I didn't feel they were doing much. The Stripe web services are trivial to integrate, so I preferred not to take the overhead of a dependency.

  8. Jeffrey Olmstead reporter

    I don't see a need to have users required to be authenticated to buy a subscription. This is why one of the fields above is the users email address (and optionally user id). This way it opens the door for us to send them a single use token (via email) to change the settings of their subscription. If a website implementer actually requires them to log in, he/she can check the box requiring authentication (as they can do now). We could also open the door up to allow a user to create an account after they have checked out (some sites do this) but I am not pushing for that at this time. That would make a complex topic more complex as we would have to migrate any data we want from local storage over to the database and I just don't see it as a top priority.

    As for commonalities on checkout, I am envisioning two scenarios:

    1. Payment gateways that have you pay off site (e.g. traditionally PayPal)
    2. Payment gateways that have you pay on site (e.g. Stripe)

    I would imagine the choice of Stripe / PayPal as it is now but that if you choose Credit Card (i.e. Stripe) then you are walked through this type of process (which seems fairly generic across payment gateways):

    • Name / Phone
    • Ship To Address (provide option of having multiple / add new ones / edit existing ones if user is logged in)
    • Shipping Options
    • Bill To Address (provide option of having multiple / add new ones / edit existing ones if user is logged in - option to choose same as Ship To Address)
    • Payment Methods
      • This would be an interface that exposes the different payment options saved for the current user (right now credit card, future could also have bank account, etc.)
      • If the user is not logged in they would just add a card / bank account
    • Review Order screen
      • This one I feel is really important to be able to provide, not exactly sure how to do with Stripe API as it would be a screen after the credit card is entered (think it could be done as Stripe provides a token to place the approved order against)

    Good point on dependency, yes, better not to rely on a library. I would only want to bring it in as code and utilize that way. Well, those are my thoughts. Look forward to hearing your ideas. If we are thinking anything similar, I can have my designer put together some concepts (I like a good visual to build off of).

  9. Bertrand Le Roy repo owner

    My concern about authentication is that I don't want us to have to reproduce a lot of what the Orchard user infrastructure already has. Single use tokens are great to protect relatively harmless resources for a short amount of time, but here we're talking about protecting highly sensitive information for a long amount of time.

    The rest sounds ok, but it's a bigger refactoring than I'd have envisioned. Looking forward to reviewing the code.

  10. Log in to comment