Django/Payments/Razorpay/Subscription/

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

Published on

How to Integrate Razorpay Payment Gateway in Django and React for the Subscription use case?
Payment gateway is used to accept payments from customers using our web application. In this blog, we are going to Razorpay to add a Subscription based payment features to a website developing using React.js and Django.


Introduction:

Razorpay is one of the modern payment gateways widely used in India. It is more reliable than its compitors. Also, it is developer-friendly and easy to integrate with any technology stack. Also, they provide so many modes of payment like UPI, Debit cards, Credit cards, Internet banking and digital wallets and QR scanner code.

With the help of Razorpay subscription API, we can integrate a regular subscription payment model to Sass or product-based applications.

 

How it works (Sequence diagram) :



 

Prerequisites:

 

Flow Diagram:




Steps:

 

In this tutorial the payments are done in Test mode, not in production mode.

The source code for both Django and react are given here: https://github.com/episyche/razorpay_subscription_django_reactjs_example

Setup instructions for Django and React.js are given in the GitHub Readme file.

 

Step 1: Setup a Razorpay account and generate API keys(public and private keys)

API keys are a unique identification number used to link your Razorpay account with any development platform like Python, Java, Ruby, Node.js etc.

Step 2: Create a subscription plan in the Razorpay dashboard

  • Go to the subscription section

  • Select Plans Tab.

  • Click on New Plan Button.




In the Popup window :

  • Enter the Plan name. (for eg: Monthly Membership)

  • Plan Description for internal use

  • Enter the Billing Frequency of the plan. ( for eg: every 1st of a month )

  • Enter the plan price (Billing Amount). ( for eg: ₹ 30 )




  • After the Successful creation of the plan, copy the plan id for payment integration purposes. The plan id is the unique identification number.

  • Using the plan Id we decide to activate monthly or yearly subscriptions. 




Step 3: Set up a basic Django project.

  • Create an empty folder with the project name.

1mkdir <project-name> 2cd <project-name> 3 4For example: 5mkdir backend 6cd backend

 

  • Inside the folder backend (project-folder) create the Django project.

1django-admin startproject core .

a. core: main app name.

b. (.) the dot symbol at the end indicates not to create a new folder. Generate files on the working directory.

c. Once the files are generated, It will be looking like the below screenshot example.

 

Step 4: Create a new Django app for the payment process “payment_razorpay”.

  • Create a Django app for handling payment logic. The name of the app is “payment_razorpay”.

1cd /<project-folder> 2 3for example : 4cd /backend
1python3 manage.py startapp payment_razorpay

a. After executing the above command an app named “payment_razorpay” will be created. An example screenshot is given below:


 

  • Add the payment_razorpay app to the INSTALLED_APPS list in settings.py

backend/core/settings.py (<project-folder>/core/settings.py)

1 2INSTALLED_APPS = [ 3 'django.contrib.admin', 4 'django.contrib.auth', 5 'django.contrib.contenttypes', 6 'django.contrib.sessions', 7 'django.contrib.messages', 8 'django.contrib.staticfiles', 9 'payment_razorpay', # <<< newly added line 10]

Sample code for the above use case can be found in the following GitHub URL.

https://github.com/episyche/razorpay_subscription_django_reactjs_example/blob/main/backend/core/settings.py

 

  • Add a new URL path for the payment_razorpay app, to the base app ( main app ) urls.py file.

backend/core/urls.py (<project-folder/core/urls.py)

1from django.contrib import admin 2from django.urls import path, include # <<< newly added line 3 4urlpatterns = [ 5 path('admin/', admin.site.urls), 6 path('payment/', include('payment_razorpay.urls')), # <<< newly added line 7]

Sample code for the above use case can be found in the following GitHub URL.

https://github.com/episyche/razorpay_subscription_django_reactjs_example/blob/main/backend/core/settings.py

 

  • Create a new urls.py file under the payment_razorpay app that we just created.

 

Step 5: Install Razorpay using pip.

  • Install Razorpay SDK using pip

1pip install razorpay

 

Step 6: Create a new function API “Create_subscription” under the payment_razorpay app

  • Create a new function API “create_subscription” under the payment_razorpay app to handle new subscription requests.

<project_folder> payment_razorpay > views.py > create_subscription (function API)

backend > payment_razorpay > views.py > create_subscription (function API)

1 2@csrf_exempt 3def create_subscription(request): 4 if request.method == "POST": 5 6 amount = int(request.POST['price']) 7 product_name = request.POST['product_name'] 8 plan_id = request.POST['plan_id'] 9 10 razorpay_subscription_res = razorpay_client.subscription.create({ 11 'plan_id': plan_id, 12 'total_count': 30, 13 'addons': [{ 14 'item': { 15 'name': product_name, 16 'currency': 'INR', 17 "amount": int(amount) * 100, 18 } 19 }], 20 }) 21 22 response_data = { 23 "callback_url": "http://127.0.0.1:8000/payment/callback", 24 "razorpay_key": "rzp_test_XjxJeSspeBN1S6", 25 "order": razorpay_subscription_res, 26 "product_name": product_name 27 } 28 29 print(response_data) 30 31 return JsonResponse(response_data)

Sample code for the above use case can be found in the following GitHub URL.

https://github.com/episyche/razorpay_subscription_django_reactjs_example/blob/main/backend/payment_razorpay/views.py

 

Step 7: Create another function API to handle the response from the payment gateway.

  • To handle the response from Razorpay payment gateway create a new function API named “subscription_callback“.

  • After successful payment, Razorpay sends payment-related information to a backend API that we specified in the callback URL. Using the data we get from Razorpay we can verify the payment status and write business logic according to the payment status.

  • The data we get from Razorpay is given below:

1{ 2 "razorpay_payment_id": "pay_29QQoUBi66xm2f", 3 "razorpay_subscription_id": "sub_KC6omw8UVrX72h", 4 "razorpay_signature": "9ef4dffbfd84f1318f6739a3ce19f9d85851857ae648f114332d8401e0949a3d" 5}
1@csrf_exempt 2def subscription_callback(request): 3 if request.method == "POST": 4 if "razorpay_signature" in request.POST: 5 payment_verification = razorpay_client.utility.verify_payment_signature(request.POST) 6 if payment_verification: 7 return JsonResponse({"res":"Subscription is now active"}) 8 # Logic to perform is payment is successful 9 # Activate logic 10 else: 11 return JsonResponse({"res":"failed"}) 12 # Logic to perform is payment is unsuccessful

Sample code for the above use case can be found in the following GitHub URL.

https://github.com/episyche/razorpay_subscription_django_reactjs_example/blob/main/backend/payment_razorpay/views.py

Step 8: Install CROS in Django

  • Set up CROS in Django, In order to avoid CROS problems between the frontend(React.js) and backend (Django).

  • pip install

1pip install django-cors-headers
  • Add CROS to MIDDLEWARE in settings.py

backend<project-name>/ core / settings.py

1MIDDLEWARE = [ 2 'django.middleware.security.SecurityMiddleware', 3 'django.contrib.sessions.middleware.SessionMiddleware', 4 'django.middleware.common.CommonMiddleware', 5 'django.middleware.csrf.CsrfViewMiddleware', 6 'django.contrib.auth.middleware.AuthenticationMiddleware', 7 'django.contrib.messages.middleware.MessageMiddleware', 8 'django.middleware.clickjacking.XFrameOptionsMiddleware', 9 'corsheaders.middleware.CorsMiddleware', # <<< new line added 10]

Sample code for the above use case can be found in the following GitHub URL.

https://github.com/episyche/razorpay_subscription_django_reactjs_example/blob/main/backend/core/settings.py

 

  • Add another variable at the end of the setings.py file.

backend<project-name>/ core / settings.py

1CORS_ORIGIN_ALLOW_ALL = True # <<< append to the end of the settings.py

Sample code for the above use case can be found in the following GitHub URL.

https://github.com/episyche/razorpay_subscription_django_reactjs_example/blob/main/backend/core/settings.py

Step 9: Integrate Razorpay payment gateway to React(frontend)

  • In this tutorial, a new component is created “Music_box.jsx”. Here we write the logic to handle the Razorpay subscription payment gateway process.

  • There is no package available in npm to install for Razorpay. We have to integrate the Razorpay from CDN using useEffect hook. The example code is given below.

1const loadScript = (src) => { 2 return new Promise((resolve) => { 3 const script = document.createElement("script"); 4 script.src = src; 5 script.onload = () => { 6 resolve(true); 7 }; 8 script.onerror = () => { 9 resolve(false); 10 }; 11 document.body.appendChild(script); 12 }); 13 }; 14 15 useEffect(() => { 16 loadScript("https://checkout.razorpay.com/v1/checkout.js"); 17 });

Sample code for the above use case can be found in the following GitHub URL.

https://github.com/episyche/razorpay_subscription_django_reactjs_example/blob/main/frontend-reactjs/src/Music_box.jsx

 

 

  • In react.js to initialize the Razorpay payment gateway, we need some additional information they are provided from the backend. Here is the list of the information we need :

    • Razorpay key id

    • Amount

    • Product name

    • currency

    • callback URL ( Django URL)

    • subscription_id

  • From the frontend(react.js) we should send the subscription plan id which is going to be activated.

1import Book1Img from './img/image1.png'; 2import { useEffect } from 'react'; 3 4export default function Music_box(){ 5 6 const loadScript = (src) => { 7 return new Promise((resolve) => { 8 const script = document.createElement("script"); 9 script.src = src; 10 script.onload = () => { 11 resolve(true); 12 }; 13 script.onerror = () => { 14 resolve(false); 15 }; 16 document.body.appendChild(script); 17 }); 18 }; 19 20 useEffect(() => { 21 loadScript("https://checkout.razorpay.com/v1/checkout.js"); 22 }); 23 24 25 function makePayment(e, price, product_name, plan_id){ 26 27 e.preventDefault(); 28 29 30 let formData = new FormData(); 31 formData.append('price', price); 32 formData.append('product_name', product_name); 33 formData.append('plan_id', plan_id); 34 35 async function paymentGateway() { 36 const url = 'http://127.0.0.1:8000/payment/new-subscription' // <<< new-subscription backend api url path 37 const res = await fetch(url, { method: 'POST', body: formData , 38 }) 39 const jsonRes = await res.json() 40 return jsonRes 41 } 42 43 paymentGateway().then((res) =>{ 44 //_________ call razorpay gateway ________ 45 var options = { 46 "key": res['razorpay_key'], 47 "amount": res['order']['amount'], 48 "currency": res['order']['currency'], 49 "callback_url": res['callback_url'], 50 prefill: { 51 "email": "nosob88243@xitudy.com", 52 "contact": "1234567890" 53 }, 54 "name": res['product_name'], 55 "subscription_id": res['order']['id'], 56 }; 57 58 var rzp1 = new window.Razorpay(options); 59 rzp1.open(); 60 }) 61 62 } 63 64 65 return( 66 <> 67 <section className='flex justify-center mt-52'> 68 <div className='rounded px-10 py-5 text-center drop-shadow-xl bg-zinc-50'> 69 <h2 className='text-3xl mb-10'>Monthly Subscription</h2> 70 <img className='w-48 mx-auto' src={Book1Img} alt="" /> 71 <p className='mt-5 text-lg'>Price : ₹ 30</p> 72 <button type='button' className="mt-2 mb-2 inline-flex items-center px-2.5 py-1.5 border border-transparent text-lg font-medium rounded shadow-sm text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" 73 onClick={e=>{makePayment(e, 1, "Monthly Subscription", "plan_KBo1U1fwUwehqK")}} 74 >Proceed to Buy</button> 75 </div> 76 </section> 77 </> 78 ) 79 80}import Book1Img from './img/image1.png'; 81import { useEffect } from 'react'; 82 83export default function Music_box(){ 84 85 const loadScript = (src) => { 86 return new Promise((resolve) => { 87 const script = document.createElement("script"); 88 script.src = src; 89 script.onload = () => { 90 resolve(true); 91 }; 92 script.onerror = () => { 93 resolve(false); 94 }; 95 document.body.appendChild(script); 96 }); 97 }; 98 99 useEffect(() => { 100 loadScript("https://checkout.razorpay.com/v1/checkout.js"); 101 }); 102 103 104 function makePayment(e, price, product_name, plan_id){ 105 106 e.preventDefault(); 107 108 109 let formData = new FormData(); 110 formData.append('price', price); 111 formData.append('product_name', product_name); 112 formData.append('plan_id', plan_id); 113 114 async function paymentGateway() { 115 const url = 'http://127.0.0.1:8000/payment/new-subscription' // <<< new-subscription backend api url path 116 const res = await fetch(url, { method: 'POST', body: formData , 117 }) 118 const jsonRes = await res.json() 119 return jsonRes 120 } 121 122 paymentGateway().then((res) =>{ 123 //_________ call razorpay gateway ________ 124 var options = { 125 "key": res['razorpay_key'], 126 "amount": res['order']['amount'], 127 "currency": res['order']['currency'], 128 "callback_url": res['callback_url'], 129 prefill: { 130 "email": "nosob88243@xitudy.com", 131 "contact": "1234567890" 132 }, 133 "name": res['product_name'], 134 "subscription_id": res['order']['id'], 135 }; 136 137 var rzp1 = new window.Razorpay(options); 138 rzp1.open(); 139 }) 140 141 } 142 143 144 return( 145 <> 146 <section className='flex justify-center mt-52'> 147 <div className='rounded px-10 py-5 text-center drop-shadow-xl bg-zinc-50'> 148 <h2 className='text-3xl mb-10'>Monthly Subscription</h2> 149 <img className='w-48 mx-auto' src={Book1Img} alt="" /> 150 <p className='mt-5 text-lg'>Price : ₹ 30</p> 151 <button type='button' className="mt-2 mb-2 inline-flex items-center px-2.5 py-1.5 border border-transparent text-lg font-medium rounded shadow-sm text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" 152 onClick={e=>{makePayment(e, 1, "Monthly Subscription", "plan_KBo1U1fwUwehqK")}} 153 >Proceed to Buy</button> 154 </div> 155 </section> 156 </> 157 ) 158 159}

Sample code for the above use case can be found in the following GitHub URL.

https://github.com/episyche/razorpay_subscription_django_reactjs_example/blob/main/frontend-reactjs/src/Music_box.jsx

Step 9: Run both Django and React.js development servers.

  • To run Django development server:

1cd <project-folder> 2 3for example: 4cd backend
1python3 manage.py runserver

 

  • To run React.js development server:

1cd <project-folder> 2 3for example: 4cd frontend
1npm start

 

Result :

  • Select the subscription plan of your choice.




  • Select UPI ID as the payment mode.

 



  • Enter the following UPI ID provided by Razorpay for Testing purposes. (success@razorpay)

 



  • After successful payment, you will get a success message as a response from the backend (Django).




  • Check subscription status on the Razorpay dashboard.


Comments