DEV Community

Cover image for Delayed and scheduled payments with Stripe
Leonidas Costas
Leonidas Costas

Posted on • Edited on • Originally published at github.com

Delayed and scheduled payments with Stripe

Hi Sparta!

In this article I will share with you how to execute delayed or scheduled payments in your React and NestJS app πŸ’³

The full source code and the documentation is available on GitHub or on FMP πŸ™‚

This payment module will be added top of the React/Node/MySQL starter. This starter has already been presented to you in this article.

How does it work ?

We'll use Stripe API in order to:

  • 1. Save customer's payment credentials
  • 2. Execute an offline payment when we want (by triggering the backend from a UI in the front, by adding a cron in the backend...).

For the first step, we'll use Stripe's SetupIntent that are meant to save credit card info that can be later used as we wish.

For the second step, we'll use Stripe's PaymentIntent that are meant to execute a payment instantly.

High picture of the workflow

  • 1. User loads the page where he can save it's card.
  • 2. Frontend asks backend to create a Stripe SetupIntent in order to let the user save it's payment credentials.
  • 3. Backend creates the SetupIntent and returns the corresponding one time secret to the frontend.
  • 4. User fills all info about it's card (number, CVV...) and does the 3DS authentication if needed. He press the "save my card" buttton.
  • 5. Backend is receiving several notifications about the SetupIntent status thanks to a Webhook. It saves all payment status in database as logs records.
  • 6. If the SetupIntent has a correct status (received from the webhook), the stripeCustomer is saved in database in the User table (so we can retrieve all it's card info later).
  • 7. When you then want to trigger an offline payment for this user, backend only needs to ask stripe all card infos for this particular stripeCustomer. It then triggers a PaymentIntent with all infos previously retrieved, and... TADA ! The delayed payment is done πŸŽ‰

Step by step guide

Step 1 - Backend

Add folder backend/stripe in your backend/src/api.
Don't forget to add StripeModule in the imports of the app.module.

Add folder backend/payment in your backend/src/api.

Don't forget to add PaymentModule in the imports of the app.module.

In the backend folder, install following dependency:
npm install stripe@8.132.0

Step 2 - Frontend

Add folder frontend/screenExample in your frontend/src/pages.

Add following code in pages.navigation.tsx :

    <Route exact path="/example" component={PaymentSiScreen}/>
Enter fullscreen mode Exit fullscreen mode

Add folder frontend/services/stripe.service.ts in your frontend/services.

In the frontend folder, install following dependency:
npm install @stripe/stripe-js@1.11.0

Step 3 - Stripe credentials

Backend:
Update stripeSecretKey in StripeController and StripeService with the secretKey from your stripe account.

Frontend:
Add stripe public key in PaymentSiScreen :

    stripeSecretKey: "pk_test_XxxXXXXxXXXXXXXxXXxxxxxXxxXXXXxXXXXXXXxXXxxxxxXxxXXXXxXXXXXXXxXXxxxxxXxxXXXXxXXXXXXXxXXxxxxx"
Enter fullscreen mode Exit fullscreen mode

Step 4 - Stripe webhook

In your Stripe account, create a webhook and publish it to production. Your webhook setup will need following events:

  • setup_intent.created
  • setup_intent.requires_action
  • setup_intent.canceled
  • setup_intent.setup_failed
  • setup_intent.succeeded
  • payment_intent.created
  • payment_intent.requires_action
  • payment_intent.requires_capture
  • payment_intent.canceled
  • payment_intent.payment_failed
  • payment_intent.succeeded

Once published, you'll have a webhookSecret available.
You can now update stripeWebhookSecretKey in StripeService with this webhookSecret.

Bonus

If you want to contact your users when they correctly saved their card or when a delayed payment failed, you can use a mailer module and send mail in the webhook function in stripe/stripe.service.ts. This other module is available here.

Conclusion

I hope this module will help you ! Do not hesitate to pin and star on GitHub if you appreciated the article ❀️

Links:

Top comments (0)