Skip to main content

Command Palette

Search for a command to run...

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.

Published
10 min read
Payments Made Easy: Razorpay Integration with React JS and Spring Boot
H

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

  1. Log in to the Razorpay Dashboard at razorpay.com.

  2. Navigate to Settings → API Keys.

  3. Generate new API keys in Test mode.

  4. Note down the Key ID (starts with rzp_test_…) and Key Secret; you’ll need these for integration.

  5. 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 RazorpayException or JSONException) 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:

    1. razorPayCreateAPICall triggers the creation of the Razorpay order from the backend.

    2. The frontend sends the order details to the Razorpay checkout modal.

    3. Upon successful payment, razorPayVerifyAPICall is 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 prefill option 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

  1. User clicks “Pay” on the frontend → triggers handlePayment.

  2. Frontend calls backend /createOrder, gets orderId.

  3. Frontend opens Razorpay Checkout with order details.

  4. User completes payment via the Razorpay interface.

  5. Razorpay returns the result to the frontend (via handler).

  6. Frontend sends a response to backend for verification (optional but safer).

  7. Backend verifies the signature and updates the order/payment status in the DB.

  8. 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_… to rzp_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! 🎉