Payments Made Easy: Razorpay Integration with React JS and Spring Boot
Everything you need to know to accept payments using Razorpay in React + Spring Boot applications.

Software Developer with 5+ years of experience in application development, proficient in Python, Java, ReactJS, and React Native. Successfully delivered several complex applications, demonstrating strong problem-solving and technical expertise.
As of 2025, integrating payment gateways into modern web applications remains a crucial yet complex task, especially when aiming for secure and scalable solutions. Razorpay, one of India’s leading payment processors, offers robust APIs for seamless integration across various tech stacks.
In this article, I’ll walk you through a comprehensive approach to integrating Razorpay’s payment gateway using ReactJS for the frontend and Spring Boot for the backend. You’ll learn how to create and manage orders, handle client-side checkout flows, verify payments securely on the server, and follow best practices for a production-ready setup.
What is Razorpay?
Razorpay is a popular payment gateway primarily serving the Indian market. It allows businesses to accept payments via multiple methods, including credit/debit cards, UPI, wallets, and net banking. Known for its easy integration, Razorpay provides APIs and SDKs for seamless payment processing in web and mobile apps.
Key features include:
Multiple Payment Methods: Cards, UPI, wallets, and more.
Easy Integration: Developer-friendly APIs and SDKs.
Security: PCI-DSS compliant, ensuring safe transactions.
Customizable Checkout: Branded, smooth payment experiences.
What we’ll cover:
Setting up a Razorpay account and generating API keys
Backend (Spring Boot): creating orders, verifying payments
Frontend (React): initiating payment via Razorpay Checkout, handling responses
Best practices, security considerations, and going live
By the end, you should have a working payment integration that you can plug into your own project.
1. Prerequisites
Before starting the Razorpay integration, make sure you have the following in place:
Razorpay Account: Sign up at the Razorpay Dashboard. Make sure to switch to Test mode for development and testing.
API Keys: Generate Test mode API keys (Key ID and Key Secret) from your Razorpay dashboard. These keys will be used to authenticate your backend server.
Development Environment:
A React JS project set up (for example, using Create React App).
A Spring Boot project configured with Maven or Gradle for backend development.
Basic Knowledge: Familiarity with REST APIs, React component lifecycle, and Spring Boot controllers will help you follow along smoothly.
2. Setting Up Razorpay
Log in to the Razorpay Dashboard at razorpay.com.
Navigate to Settings → API Keys.
Generate new API keys in Test mode.
Note down the Key ID (starts with
rzp_test_…) and Key Secret; you’ll need these for integration.When you’re ready to go live, switch to Live mode and use the corresponding live keys.
Note: Razorpay may ask you to complete onboarding and KYC (Know Your Customer) verification before you can access the dashboard or go live.
If your goal is to develop or demo your Razorpay integration, stay in Test Mode, where:
No real money is transferred
No KYC is required
You can fully test payments, refunds, orders, and webhooks
If the dashboard prompts for KYC, it’s likely because you switched into Live Mode. To avoid this during development, make sure to remain in Test Mode.

3. Backend Integration with Spring Boot
3.1 Add Razorpay Java SDK Dependency
Add the Razorpay Java SDK to your pom.xml:
<dependency>
<groupId>com.razorpay</groupId>
<artifactId>razorpay-java</artifactId>
<version>1.4.4</version> <!-- Use the latest available version -->
</dependency>
3.2 Configure Application Properties
Add Razorpay credentials to your application.properties:
razorpay.key_id = rzp_test_***********
razorpay.key_secret = ************************
razorpay.currency = INR
Alternatively, if you're using application.yml, add the following:
razorpay:
key:
id: rzp_test_***********
secret: ************************
currency: INR
payment:
capture: true
3.3 Create Razorpay Client Bean
Create a Spring @Configuration class to initialize the Razorpay client with your API keys. This will load your properties into the configuration class.
package com.FoodOnline.Config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties(prefix = "razorpay")
public class RazorPayConfig {
private Key key = new Key();
private String currency;
private Payment payment = new Payment();
public static class Key {
private String id;
private String secret;
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getSecret() { return secret; }
public void setSecret(String secret) { this.secret = secret; }
}
public static class Payment {
private boolean capture;
public boolean isCapture() { return capture; }
public void setCapture(boolean capture) { this.capture = capture; }
}
// Getters & Setters
public Key getKey() { return key; }
public void setKey(Key key) { this.key = key; }
public String getCurrency() { return currency; }
public void setCurrency(String currency) { this.currency = currency; }
public Payment getPayment() { return payment; }
public void setPayment(Payment payment) { this.payment = payment; }
}
This approach uses Spring Boot's @ConfigurationProperties to automatically bind the properties from application.properties or application.yml.
3.4 Implement Order Creation Endpoint
Create a REST controller to accept order requests and create Razorpay orders:
package com.FoodOnline.Payments.Controller;
import com.FoodOnline.Config.RazorPayConfig;
import com.razorpay.*;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/controller/api/payments")
public class RazorPayController {
@Value("${razorpay.key.id}")
public String keyId;
@Autowired
private RazorPayConfig razorpayConfig;
@PostMapping("/create-order")
public ResponseEntity<?> createOrder(@RequestBody Map<String, Object> data) throws RazorpayException {
int amount = (int) data.get("amount");
RazorpayClient client = new RazorpayClient(
razorpayConfig.getKey().getId(),
razorpayConfig.getKey().getSecret()
);
JSONObject orderRequest = new JSONObject();
orderRequest.put("amount", amount);
orderRequest.put("currency", razorpayConfig.getCurrency());
orderRequest.put("payment_capture", razorpayConfig.getPayment().isCapture() ? 1 : 0);
Order order = client.orders.create(orderRequest);
Map<String, Object> response = new HashMap<>();
response.put("orderId", order.get("id"));
response.put("amount", amount);
response.put("currency", razorpayConfig.getCurrency());
response.put("keyId", keyId);
return ResponseEntity.ok(response);
}
}
This code handles the order creation, including setting the amount, currency, and whether payment should be captured automatically.
3.5 Verify Payment Signature
To ensure the payment is legitimate, verify the signature on the server side. Razorpay sends a signature when the payment is processed. You must verify it to ensure data integrity.
package com.FoodOnline.Payments.Controller;
import com.FoodOnline.Config.RazorPayConfig;
import com.razorpay.*;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/controller/api/payments")
public class RazorPayController {
@Value("${razorpay.key.id}")
public String keyId;
@Autowired
private RazorPayConfig razorpayConfig;
@PostMapping("/verify-payment")
public ResponseEntity<Map<String, String>> verifyPayment(@RequestBody Map<String, String> payload) {
String orderId = payload.get("razorpay_order_id");
String paymentId = payload.get("razorpay_payment_id");
String signature = payload.get("razorpay_signature");
Map<String, String> response = new HashMap<>();
try {
String generatedSignature = Utils.getHash(orderId + "|" + paymentId, razorpayConfig.getKey().getSecret());
if (generatedSignature.equals(signature)) {
response.put("status", "success");
} else {
response.put("status", "failure");
}
} catch (Exception e) {
response.put("status", "error");
}
return ResponseEntity.ok(response);
}
}
This endpoint handles the payment verification process.
It compares the signature generated using the order ID and payment ID with the signature sent by Razorpay.
If they match, the payment is verified and marked as successful.
Improvements & Notes:
Exception Handling: It's a good practice to handle exceptions properly (e.g., for
RazorpayExceptionorJSONException) in production code.Utils Class: The
Utils.getHash()function used to generate the HMAC signature is a utility function. You can implement it as follows:import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.security.NoSuchAlgorithmException; public class Utils { public static String getHash(String data, String key) throws Exception { try { Mac sha256_HMAC = Mac.getInstance("HmacSHA256"); SecretKeySpec secret_key = new SecretKeySpec(key.getBytes(), "HmacSHA256"); sha256_HMAC.init(secret_key); byte[] hashBytes = sha256_HMAC.doFinal(data.getBytes()); return javax.xml.bind.DatatypeConverter.printHexBinary(hashBytes).toLowerCase(); } catch (NoSuchAlgorithmException | java.security.InvalidKeyException e) { throw new Exception("Error generating hash", e); } } }Security Considerations: Ensure you never log sensitive information like API keys or payment details. In a production environment, make sure all communications are done over HTTPS.
4. Frontend Integration with React JS
4.1 Include Razorpay Checkout Script
To integrate Razorpay's checkout functionality, add the following script tag to your public/index.html:
<script src="https://checkout.razorpay.com/v1/checkout.js"></script>
This script will load the Razorpay Checkout SDK, which is required to initiate the payment process.
4.2 Create Checkout Component
Next, create a React component that will handle the payment process and interact with your backend.
RazorpayCheckout.js:
import {razorPayCreateAPICall, razorPayVerifyAPICall} from '../services/APIsService.js';
import { toast } from 'react-toastify';
const RazorpayCheckout = ({ amountInINR }) => {
const handlePayment = async () => {
try {
const amountToPay = Math.round(amountInINR * 100);
const response = await razorPayCreateAPICall(amountToPay); // await here
const { orderId, amount, currency, keyId } = response.data;
if (!window.Razorpay) {
toast.error("Razorpay SDK not loaded");
return;
}
const options = {
key: keyId, // public key from backend
amount,
currency,
order_id: orderId,
name: "Food Online",
description: "Order Payment",
handler: async (response) => {
const verifyRes = await razorPayVerifyAPICall(response.razorpay_order_id, response.razorpay_payment_id, response.razorpay_signature);
if (verifyRes.data.status === "success") {
toast.success("Payment Successful!");
} else {
toast.error("Payment Verification Failed!");
}
},
prefill: {
name: "Himanshu Jha",
email: "demo@example.com",
contact: "9999999999",
},
theme: { color: "#528FF0" },
};
const rzp = new window.Razorpay(options);
rzp.open();
} catch (error) {
console.error("Payment initiation error:", error);
toast.error("Something went wrong while initiating payment.");
}
};
return (
<button
onClick={handlePayment}
style={{
marginTop: "10px",
background: "#ff6b35",
width: "100%",
color: "white",
padding: "12px",
border: "none",
borderRadius: "12px",
fontSize: "16px",
fontWeight: "bold",
cursor: "pointer",
transition: "background 0.2s ease, transform 0.1s ease",
}}
onMouseOver={(e) => e.currentTarget.style.transform = "scale(1.05)"}
onMouseOut={(e) => e.currentTarget.style.transform = "scale(1)"}
>
Proceed to Checkout
</button>
);
};
export default RazorpayCheckout;
Key Points:
Amount Conversion: Razorpay works with paise (1 INR = 100 paise), so ensure that the amount passed to the Razorpay API is multiplied by 100.
API Call Flow: The flow is as follows:
razorPayCreateAPICalltriggers the creation of the Razorpay order from the backend.The frontend sends the order details to the Razorpay checkout modal.
Upon successful payment,
razorPayVerifyAPICallis called to verify the payment.
4.3 Backend API Calls
APIsService.js:
This file contains the API service functions to call the backend endpoints for order creation and payment verification.
import axios from "axios";
const REST_API_BASE_URL = "http://localhost:8080"
export const razorPayCreateAPICall=(amount)=>{
const token = 'Bearer ' + localStorage.getItem('token')
const url = REST_API_BASE_URL+`/controller/api/payments/create-order`;
const headers = {
'Content-type':'application/json',
'Authorization': token,
};
const body ={amount};
return axios.post(url, body, {headers});
};
export const razorPayVerifyAPICall=(razorpay_order_id, razorpay_payment_id, razorpay_signature)=>{
const token = 'Bearer ' + localStorage.getItem('token')
const url = REST_API_BASE_URL+`/controller/api/payments/verify-payment`;
const headers = {
'Content-type':'application/json',
'Authorization': token,
};
const body ={razorpay_order_id, razorpay_payment_id, razorpay_signature};
return axios.post(url, body, {headers});
};
4.4 Use Razorpay Checkout in Your App
In your shopping cart or payment page, you can use the RazorpayCheckout component like this:
import RazorpayCheckoutButton from "./RazorpayCheckout";
// Assuming total is the total amount to be paid (in INR)
<RazorpayCheckoutButton amountInINR={total.toFixed(2)} />
Improvements & Clarifications:
Error Handling: It's crucial to handle errors gracefully. For instance, if the Razorpay SDK isn't loaded, an error toast is displayed. Additionally, errors in payment initiation or verification are captured and displayed to the user.
Prefill Information: The
prefilloption is used to prefill the customer's details in the Razorpay Checkout form. Make sure you pass dynamic data if available (e.g., user name, email, and contact).API Token: It's assumed that you're using
localStorage.getItem('token')for authentication. You may want to handle token expiration or invalidation.
5. Putting It All Together: Flow Overview
User clicks “Pay” on the frontend → triggers
handlePayment.Frontend calls backend
/createOrder, getsorderId.Frontend opens Razorpay Checkout with order details.
User completes payment via the Razorpay interface.
Razorpay returns the result to the frontend (via
handler).Frontend sends a response to backend for verification (optional but safer).
Backend verifies the signature and updates the order/payment status in the DB.
You may show success/failure to the user and proceed accordingly.
Below is a small overview of my test application:





6. Best Practices & Tips
Always use Test mode keys during development. Switch to Live keys for production.
Verify payment signatures on the server, not only on the client, to avoid spoofing.
Store order and payment metadata (orderId, paymentId, signature) in your database for records and auditing.
Use HTTPS in production when dealing with payments.
Handle edge cases: payment failure, network interruptions, and payment timeouts.
Integrate webhooks (from Razorpay) for real‑time payment status updates (optional advanced step).
Log errors for failed payments and monitor via the dashboard.
Currency handling: Razorpay expects the amount in the smallest currency unit (e.g., paise for INR).
UI/UX: Give clear feedback to users before, during, and after the payment flow.
7. Going Live & Deployment Considerations
Switch your keys from
rzp_test_…torzp_live_…in production.Verify that your domain is registered and allowed in Razorpay settings (if you configure domain whitelisting).
Ensure CORS, security, and authentication are configured properly for your backend.
Test thoroughly with different payment methods (cards, UPI, wallets) as supported by Razorpay.
Monitor live transactions via the Razorpay Dashboard.
Ensure fallback/payment retry workflows are in place for failed payments.
8. Conclusion
Integrating a payment gateway is a critical feature for many modern web applications. With React JS on the frontend and Spring Boot on the backend, you can implement a robust and secure payment solution using Razorpay. In this guide, you’ve seen how to set up your account, create orders, handle checkout, verify payments, and follow best practices for production.
Start with a small amount in Test mode, ensure everything works smoothly, and then move to Live mode. With this in place, your users can seamlessly make payments, and you , as the developer, can manage the flow with confidence.
Happy coding, and may your payments always succeed! 🎉


