How to setup Stripe subscriptions using custom checkout (rather than Stripe checkout page)

Hello all,


My dad (Wapper forum name (and real name) @Antony ) and I have spent the best part of 2 days trying to allow my site to setup Stripe subscriptions within a custom checkout form. For customer experience reasons, I didn’t want to divert users to the Stripe checkout page so was determined to create the subscriptions within my page.

We have finally managed to do it, so I thought I would share how we did this for anyone wanting to do the same!



OUR INITIAL APPROACH

Since my products also include a one-off payment plan (rather than subscription), I needed to accommodate both.

For one-off payment:
On the server-side, we setup a server action to create a payment intent (using the ‘create paymentintent template’ action).

On the client-side we had a stripe checkout form that linked to the server action.

For creating a subscription:
We added a second server action dedicated to creating the subscription.

Since a subscription requires a customer to be created in stripe and for that customer to have a default payment method, we added these steps into this server action before adding the create subscription action.





THE PROBLEM

These server actions worked fine BUT the paymentintent was taking an initial payment AND the subscription server action was taking the first payment for the subscription, which ended up with the payment method being charged twice.






THE SOLUTION

We needed to capture the card details for the payment method, create the customer and set the payment method as the customer’s default WITHOUT taking any payment so that the create subscription action can handle the initial payment.

We therefore used the stripe card element on the client side and set a button so that on click, it created a payment method from the stripe card element.

<button id="btn_subscribe" class="btn btn-success active" dmx-on:click="card_info.createPaymentMethod()" dmx-show="var_chosenplan.value!='oo'">Subscribe</button>

This successfully created the payment method and then we needed to pass the payment method ID to the create subscription server action. Using the dynamic event on the stripe card element called payment_method_created, we could use syntax of f_chosenplan.card_info.paymentMethod.id to call the payment method ID.

This syntax broken down is:

form ID . stripe card element ID . paymentMethod . id
f_chosenplan.card_info.paymentMethod.id

Code below…

<dmx-stripe-card id="card_info" dmx-on:payment_method_created="stripe_subscription.load({chosenplan: var_chosenplan.value, inp_email_pay: inp_email_pay.value, inp_last_name_pay: inp_last_name_pay.value, inp_first_name_pay: inp_first_name_pay.value, inp_address_pay: inp_address_pay.value, inp_town_city_pay: inp_town_city_pay.value, inp_postcode_pay: inp_postcode_pay.value, inp_payment_method_pay: f_chosenplan.card_info.paymentMethod.id})"></dmx-stripe-card>





So to summarise how it is now setup:

BIG PICTURE


Stripe checkout form - collects customer details eg. name, email and contains the stripe card element.






Form submit button - calls my server action stripe_checkout, which creates the customer in stripe and then creates the payment intent. Since this works in conjunction with the stripe checkout form, it takes the payment as well.

<button id="btn_pay" class="btn active btn-success" type="submit" dmx-on:click="var_f_chosenplan_oneoff_processing.setValue(1)" dmx-show="var_chosenplan.value=='oo'">Pay</button>




stripe_checkout server action:






Subscribe button (not a submit button) - this uses the stripe card element on the client side to create a payment method. We then use the ‘payment method created’ event within the stripe card element to call my stripe_subscription server action.

<button id="btn_subscribe" class="btn btn-success active" dmx-on:click="card_info.createPaymentMethod()" dmx-show="var_chosenplan.value!='oo'">Subscribe</button>




stripe_subscription server action - this creates the customer based on the fields in the form (using $_GET variables), attaches the newly created payment method to the customer, and then updates the customer to make this payment method their default payment method. Finally, it creates the subscription (including taking the first payment).

The first challenge with this stripe_subscription server action was getting the product price into the ‘items’ field. This required 3 steps to create an array structure to pass through to stripe.



First created the array list:






With the below schema:






Then added in the array list - giving the price the value of the price_id from stripe for that product






Then had to use a get array list value to set the value up.


Another challenge was using the appropriate syntax to pass the payment method ID into the server action (solution for this explained in THE SOLUTION section above).



Final stripe_subscription server action:





This is now working for me so I am feeling very relieved and very grateful to my clever Dad for his help!

If you have any questions, please feel free to ask and I will do my best to help you make it work for you.

There is a chance I will need to divert your questions to @Antony if they are too complex as I am still a relative beginner to all of this!

Thanks,

Leo

5 Likes

Hi Leo

This is excellent so thank you for taking the time to show how you did it. I’m sure it will be mega helpful to others.

I assume you’ve also set up some Stripe Webhooks? Have you done anything more than just updating the data to show when the payment was successful? Would be good to see anything on that side of things as, again, it will be helpful to others trying to achieve a similar solution.

Well played with it all. I’ve been following a lot of your dad’s posts ever since our first meetup back in 2020.

Cheers, Jon.

2 Likes

Hi Jon,

Thanks for your kind response - I do hope people find it useful!

I haven’t used stripe webhooks yet as I haven’t delved into the database side of things yet. My main focus was getting the functionality of the subscription and payments side working and then I can build the rest of it around that.

Thanks,

Leo

Cool. You’ll find the webhooks to be very good and pretty straightforward. You just add one based on the event from Stripe which you want to capture (like charge.succeeded) and Wappler then gives you all the fields which are posted to it so you can update your data easily. You need them to establish that the payment was actually successful.

2 Likes