episyche logo

Episyche

Django/Payments/Stripe/

How to Integrate Stripe Payment Gateway in Django and React for the Subscription use case?

Published on

How to Integrate Stripe Payment Gateway in Django and React for the Subscription use case?
Subscription management provides your users with the best user experience on any device anywhere. We will go through all the steps required to build a complete Subscription Payments system using Stripe with React and Django here

Introduction:

With Subscriptions, customers make recurring payments for access to a product. Subscriptions require you to retain more information about your customers than one-time purchases do because you need to charge customers in the future.

Flow diagram:


flow diagram

How it works:


how it works

Prerequisites :

Steps:

Step 1: Signup and Login to Stripe

If you don't have an Stripe account ( ), please proceed with the signup option, otherwise, log in with your existing credentials.

Step 2: Retrieve the Stripe API Keys

  • In the Stripe dashboard click Developers

  • Then, click API keys, In the API keys section, find the Publishable key and Secret key. Copy them and paste it into a local text file. These Key`s will be used to interact with Stripe

:warning:

Your Secret key used in backend only . Don't use in frontend

api key

Step 3: Create a product

  • To add subscription in your project , first you need to create a product

  • In stripe dashboard , click Products > Add a product



product

  • On the next page fill the following details (i.e. Name , Pricing model , Price , Billing period )



product


product


  • After filling the details click Save product

  • To check your products , In Stripe dashboard go to Products.



stripe

  • Click the product which you created in the above step . Yow will find the price id. Copy them and use it in your front end to access the subscription.



stripe

Step 4:Django Backend Creation

  • Create a django project named stripe_django using the following command.

1django-admin startproject stripe_django
  • Navigate to the project directory which you have created in the above step and create an app named subscription using the following command.

1cd stripe_django 2python manage.py startapp subscription
  • The project structure is given below



project structure

  • Install the stripe python package using pip

1pip install --upgrade stripe
  • Update the django settings.py file with following items.

    • In INSTALLED_APPS section add your app name (i.e. subscription)

    • Append STRIPE_SECRET_KEY(i.e. from Step 2: Retrieve the Stripe API Keys ) at end of settings.py file to allow django to access stripe.

1#settings.py 2 3INSTALLED_APPS = [ 4 ..... 5 'subscription' 6] 7. 8. 9. 10 11#stripe 12STRIPE_SECRET_KEY = <YOUR_STRIPE_SECRET_KEY>


installed app


secret key



A sample settings.py file can be found in the following git repository file.

  • Navigate to subscription django app directory, and create a CreateSubscription class in views.py.

  • To access stripe in your class. Import it (i.e. import stripe) and add your API key with stripe( stripe.api_key = <your_stripe_secret_key>

1import stripe 2 3stripe.api_key = settings.STRIPE_SECRET_KEY 4 5class CreateSubscription(APIView): 6 def post(self , request): 7 data = request.data 8 try: 9 checkout_session = stripe.checkout.Session.create( 10 line_items = [ 11 { 12 'price' : data['price_id'], 13 'quantity' : 1 14 } 15 ], 16 mode = 'subscription', 17 success_url = FRONTEND_SUBSCRIPTION_SUCCESS_URL +"?session_id={CHECKOUT_SESSION_ID}", 18 cancel_url = FRONTEND_SUBSCRIPTION_CANCEL_URL 19 ) 20 return redirect(checkout_session.url , code=303) 21 except Exception as err: 22 raise err


A sample views.py file can be found in the following git repository file.

  • After creating the class add urls.py file under your subscription django app.



subscription

  • In your core folder navigate to urls.py and add your path with <appname> and <url_filename>(i.e. created in the above step) .Your core urls.py settings like below.

1from django.contrib import admin 2from django.urls import path , include 3 4urlpatterns = [ 5 path('admin/', admin.site.urls), 6 path('subscription/', include('<your_app_name>.<url_filename>')), 7]

project structure


A sample urls.py(core folder) file can be found in the following git repository file.

  • Now , In your subscription app urls.py add your path with the class CreateSubscription

1from subscription import views 2from django.urls import path 3from .views import* 4 5 6urlpatterns = [ 7 path('create-subscription/' , CreateSubscription.as_view()), 8]


urls



A sample urls.py(subscription) file can be found in the following git repository file.

Step 4: Setup webhook to test locally

A webhook is an endpoint on your server that receives requests from Stripe, notifying you about events that happen on your account such as a customer disputing a charge or a successful recurring payment.

  • Navigate to checkout django app directory, and create a Webhook Class in views.py.

1class WebHook(APIView): 2 def post(self , request): 3 """ 4 This API handling the webhook . 5 6 :return: returns event details as json response . 7 """ 8 request_data = json.loads(request.body) 9 if webhook_secret: 10 # Retrieve the event by verifying the signature using the raw body and secret if webhook signing is configured. 11 signature = request.META['HTTP_STRIPE_SIGNATURE'] 12 try: 13 event = stripe.Webhook.construct_event( 14 payload=request.body, 15 sig_header=signature, 16 secret=webhook_secret 17 ) 18 data = event['data'] 19 except ValueError as err: 20 raise err 21 except stripe.error.SignatureVerificationError as err: 22 raise err 23 # Get the type of webhook event sent - used to check the status of PaymentIntents. 24 event_type = event['type'] 25 else: 26 data = request_data['data'] 27 event_type = request_data['type'] 28 data_object = data['object'] 29 30 if event_type == 'checkout.session.completed': 31 # Payment is successful and the subscription is created. 32 # You should provision the subscription and save the customer ID to your database. 33 print("-----checkout.session.completed----->",data['object']['customer']) 34 elif event_type == 'invoice.paid': 35 # Continue to provision the subscription as payments continue to be made. 36 # Store the status in your database and check when a user accesses your service. 37 # This approach helps you avoid hitting rate limits. 38 print("-----invoice.paid----->", data) 39 elif event_type == 'invoice.payment_failed': 40 # The payment failed or the customer does not have a valid payment method. 41 # The subscription becomes past_due. Notify your customer and send them to the 42 # customer portal to update their payment information. 43 print("-----invoice.payment_failed----->",data) 44 else: 45 print('Unhandled event type {}'.format(event_type)) 46 47 return JsonResponse(success=True, safe=False)

A sample views.py file can be found in the following git repository file.

  • Now , In your checkout app urls.py add your path with the class WebHook

1from subscription import views 2from django.urls import path 3from .views import* 4 5urlpatterns = [ 6 path('create-subscription/' , CreateSubscription.as_view()), 7 path('webhook-test/' , WebHook.as_view()) , 8]


subscription


A sample urls.py(subscription) file can be found in the following git repository file.

  • In stripe dashboard click Developers > Webhooks > Test in a local environment



webhook

  • After clicking Test in local environment button, the following screen will appear, which will explain the steps needs to connect the django with stripe webhook.

  • Follow the instructions mentioned in above screen.

    • Click the Download CLI from the above screen, Download the CLI. unzip it and run the executable file (i.e. In my case its windows system, therefore I am gonna run stripe.exe file)

    • Navigate to the CLI tool installation directory(i.e. stripe.exe file location)

    • Open the Windows Command prompt and proceed with the following steps

      • Log in Stripe account using the below command

        • 1stripe login
        • You will get a pairing code like below , press Enter



webhook

        • After press Enter , It will redirect to stripe and ask to Verify that the pairing code screen like below. click Allow access



allow access

        • After clicking Allow access . you will get a screen like below



success

      • Forward events to your webhook

        • 1stripe listen --forward-to localhost:8000/<your_webhook_api_url> 2 3For example: 4stripe listen --forward-to localhost:8000/webhook-test/


          pairing key

        • After executing above command, webhook signing secret is generated. ( for example <whsec_15441... >). Copy them and paste it in a text file. This key used to handle the webhook.

        • Also add your webhook signing secret in settings.py file.

          1#stripe 2STRIPE_SECRET_KEY = <YOUR_STRIPE_SECRET_KEY> 3STRIPE_WEBHOOK_SECRET = <YOUR_WEBHOOK_SECRET>


secret key



  • After completing the steps . Click Done



webhook

  • Complete Django example in the following github repo.

Step 4: React Frontend Creation

  • Run the following command to create a React project.

1npx create-react-app stripe_react
  • Navigate to the created project directory

1cd stripe_react
  • Add a .env file and add your Stripe Publishable key

1REACT_APP_STRIPE_KEY=pk_test_<YOUR_PUBSHICHABLE_KEY>

A sample .env file can be found in the following git repository file.

  • Create a Config folder under src . After, under the Config folder create config.js file . This file can connect with the backend.

1export const API_URL = process.env.REACT_APP_API_URL || 'http://localhost:8000' 2export const REACT_APP_STRIPE_KEY = process.env.REACT_APP_STRIPE_KEY || 'pk_test_<YOUR_PUBSHICHABLE_KEY>'

A sample config.js file can be found in the following git repository file.

  • Under the src folder create a folder named Component that contains Subscription.js , Success and failure redirect .js files.

  • Final project structure is given below


project structure

 
  • In your package.json add the following dependencies

1{ 2 "name": "stripe-react", 3 "version": "0.1.0", 4 "private": true, 5 "dependencies": { 6 "@stripe/react-stripe-js": "^1.8.1", 7 "@stripe/stripe-js": "^1.31.0", 8 "@stripe/stripe-react-native": "^0.12.0", 9 ... 10 ... 11 "react-router-dom": "^6.3.0", 12 }

Module not found: Error: Can't resolve '@stripe/stripe-js/pure' – >npm install @stripe/stripe-js

Module not found: Error: Can't resolve 'react-router-dom' – > npm install react-router-dom

  • In subscription.js add two subscription option (for example , monthly and yearly subscription). These two forms having the hidden input field with price id to get the subscription. In form action add your backend api URL(for example – http://localhost:8000/subscription/create-subscription/ )

  • Add two buttons monthly and yearly subscription

1import { API_URL } from '../Config/config'; 2 3const Subscription = () => { 4 return ( 5 <> 6 <h1>Subscription</h1> 7 <div className='subscription'> 8 <div className='starter-div' > 9 <h2>Starter plan</h2> 10 <img className='month-img' src='https://img.freepik.com/free-vector/subscriber-concept-illustration_114360-3453.jpg?t=st=1654685116~exp=1654685716~hmac=b67fdd003003bc4f477b5184b2201a36a5a88ebefc2552ee7f4f723a2acef85f&w=740'></img> 11 12 <form action={`${API_URL}/subscription/create-subscription/`} method="POST"> 13 <input type="hidden" name="price_id" value="price_1LaFt5SE9c6We7uyk0J5QRnG" /> 14 <button className="btn-month" type="submit" >&#8377;30 / Month</button> 15 </form> 16 </div> 17 <br></br> 18 <div className='premium-div'> 19 <h2>Premium plan</h2> 20 <img className='year-img' src='https://img.freepik.com/free-vector/subscriber-concept-illustration_114360-2949.jpg?t=st=1654651458~exp=1654652058~hmac=fc1ea117f4198608284f1fea2f5af8f4c50f75692b80c711ad5c93793d0f3ab0&w=740'></img> 21 <form action={`${API_URL}/subscription/create-subscription/`} method="POST"> 22 <input type="hidden" name="price_id" value="price_1LaFt5SE9c6yk0J5QRnG" /> 23 <button className="btn-year" type="submit" >&#8377;350 /Year</button> 24 </form> 25 </div> 26 27 </div> 28 <br> 29 </br> 30 </> 31 ); 32} 33 34export default Subscription;

A sample Subscription.js file can be found in the following git repository file.

  • When you click the button it calls backend api. In backend performs stripe subscription.

  • After completing your payment you need to redirect based on subscription status. So , you have to add Success.js and Cancel.js

  • In success.js add some success message like Subscription successful.

1import { API_URL } from '../Config/config'; 2 3const Success = () => { 4 5 return ( 6 <> 7 <section> 8 <div class="product Box-root"> 9 10 <div class="description Box-root"> 11 <h3>Your plan Subscribed successful!</h3> 12 </div> 13 </div> 14 </section> 15 </> 16 ) 17} 18 19export default Success
  • In Cancel.js add some failure messages like subscription failed.

1const Cancel = () => { 2 return ( 3 <> 4 <section> 5 <p>Subscription Failed . back to pay!</p> 6 </section> 7 </> 8 ) 9} 10 11export default Cancel
  • In App.js add some routing for pages which you created in above steps.

1import './index.css' 2import React from 'react' 3import { Elements } from '@stripe/react-stripe-js' 4import { loadStripe } from "@stripe/stripe-js/pure" 5import Subscription from "./Component/Subscription" 6import Success from './Component/Success' 7import Cancel from './Component/Cancel' 8import { BrowserRouter as Router, Routes, Route } from "react-router-dom" 9import { REACT_APP_STRIPE_KEY } from './Config/config'; 10 11const stripe_key = REACT_APP_STRIPE_KEY 12const stripePromise = loadStripe(stripe_key) 13 14function App() { 15 return ( 16 <> 17 <Elements stripe={stripePromise} > 18 <Router> 19 <Routes> 20 <Route exact path='subscription/' index element={<Subscription />} /> 21 <Route exact path='subscription/success/' element={<Success/>} /> 22 <Route exact path='subscription/failed/' element={<Cancel/>} /> 23 </Routes> 24 </Router> 25 26 </Elements> 27 </> 28 ); 29} 30 31export default App;

loadStripe – It will load stripe payment pages in React.

  • run the project using following command.

1npm start

Result:

After run both backend and frontend , If we click on the monthly or yearly button, it will redirect to the stripe payment page See the below image:


result



result


  • In Payment page give some testing data and click Subscribe



result


result

  • If payment success it will redirect the success page



result

  • Check in your stripe dashboard if subscription created status . In stripe dashboard click Payments > Subscriptions



result

Comments