Razorpay Payment Gateway Integration in Java Spring Boot

In this tutorial, we will learn how to integrate Razorpay Payment Gateway in a Spring Boot Application. We will add Razorpay checkout option with different payment amounts. We will be using Manual Javascript methods to add razorpay frontend. For demo purpose, we will be using Razorpay in Test Mode, once we have implemented, you can make it live. So lets get started.

Spring Boot Razorpay Integration

Setup Razorpay Account

First of all, you need to create a razorpay account and then in settings, generate API key. Once api key generate, you will find rzp_key_secret, rzp_key_id, save it for further usage. For now we will set razorpay account in test mode. So from navbar, choose Test mode instead of Live Mode.

Installing Razorpay Dependencies

Install Razorpay using Maven or Gradle, by adding bellow dependency. Currently, we are using 1.4.3 version, you can use latest one from here.

// Maven
<dependency>
    <groupId>com.razorpay</groupId>
    <artifactId>razorpay-java</artifactId>
    <version>1.4.3</version> //x.y.z = the version you want to install
</dependency>

Or

// Gradle
implementation 'com.razorpay:razorpay-java:1.4.3'

Implement of Razorpay in Project

Add the bellow properties in application.properties files and replace with your razorpay id and secret. You can change currency and company_name as well.

# Razorpay
rzp_key_id=rzp_test_0QasdfVab6AeJ
rzp_key_secret=xzuJzMAbadsdbItsCjeQOZPgK
rzp_currency=INR
rzp_company_name=YOUR_COMPANY_NAME

Controller for Razorpay

Simple Controller for Displaying Payment Page

@RequestMapping(value = {"/payment"}, method = RequestMethod.GET)
public String payment(Model model){
    model.addAttribute("rzp_key_id", env.getProperty("rzp_key_id"));
    model.addAttribute("rzp_currency", env.getProperty("rzp_currency"));
    model.addAttribute("rzp_company_name", env.getProperty("rzp_company_name"));
    return "users/payment";
}

Now we will create controller rest api for creating Order Id. Which we will call using Ajax from

@GetMapping("/payment/createOrderId/{amount}")
@ResponseBody
public String createPaymentOrderId(@PathVariable String amount) {
String orderId=null;
try {
RazorpayClient razorpay = new RazorpayClient(env.getProperty("rzp_key_id"), env.getProperty("rzp_key_secret"));
JSONObject orderRequest = new JSONObject();
orderRequest.put("amount", amount); // amount in the smallest currency unit
orderRequest.put("currency", env.getProperty("rzp_currency"));
orderRequest.put("receipt", "order_rcptid_11");

Order order = razorpay.orders.create(orderRequest);
orderId = order.get("id");
} catch (RazorpayException e) {
// Handle Exception
System.out.println(e.getMessage());
}
return orderId;
}

Bellow is payment.html, basically in this we have implement 2 cards, where each card has a button, on button click it will call CreateOrderID(amount, contactCounts, description) function. In CreateOrderID we have have passed different values on different buttons. Then we will do a Ajax call which will call /payment/createOrderId/{amount} and razorpay will handle it.

<div class="container">
    <div class="row">

        <div class="col-sm-4 pb-5">
            <div class="card">
                <div class="card-body m-4">
                    <h5 class="card-title">Gold
                        <span class="text-warning">
                          <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-star-fill mb-1" viewBox="0 0 16 16">
                            <path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
                              </svg>
                              <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-star-fill mb-1" viewBox="0 0 16 16">
                              <path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
                            </svg>
                        </span>
                    </h5>
                    <div class="mt-auto mb-4">
                        <span class="fw-bold fs-2">₹ 1000</span> / 125 contacts
                    </div>
                    <ul class="list-unstyled">
                        <li class="mb-3">
                            <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-check2" viewBox="0 0 16 16">
                                <path d="M13.854 3.646a.5.5 0 0 1 0 .708l-7 7a.5.5 0 0 1-.708 0l-3.5-3.5a.5.5 0 1 1 .708-.708L6.5 10.293l6.646-6.647a.5.5 0 0 1 .708 0z"/>
                            </svg> 125 contacts
                        </li>
                        <li class="mb-3">
                            <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-check2" viewBox="0 0 16 16">
                                <path d="M13.854 3.646a.5.5 0 0 1 0 .708l-7 7a.5.5 0 0 1-.708 0l-3.5-3.5a.5.5 0 1 1 .708-.708L6.5 10.293l6.646-6.647a.5.5 0 0 1 .708 0z"/>
                            </svg> 25% Discount
                        </li>
                    </ul>
                    <div class="d-grid gap-2">
                        <button class="btn btn-primary" type="button" onclick="CreateOrderID(1000, 125, '1000 INR - 125 Contacts')">Buy Now</button>
                    </div>
                </div>
            </div>
        </div>

        <div class="col-sm-4 pb-5">
            <div class="card">
                <div class="card-body m-4">
                    <h5 class="card-title">Platinum
                        <span class="text-warning">
                          <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-star-fill mb-1" viewBox="0 0 16 16">
                            <path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
                          </svg>
                          <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-star-fill mb-1" viewBox="0 0 16 16">
                            <path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
                          </svg>
                            <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-star-fill mb-1" viewBox="0 0 16 16">
                            <path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
                          </svg>
                        </span>
                    </h5>
                    <div class="mt-auto mb-4">
                        <span class="fw-bold fs-2">₹ 1500</span> / 200 contacts
                    </div>
                    <ul class="list-unstyled">
                        <li class="mb-3">
                            <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-check2" viewBox="0 0 16 16">
                                <path d="M13.854 3.646a.5.5 0 0 1 0 .708l-7 7a.5.5 0 0 1-.708 0l-3.5-3.5a.5.5 0 1 1 .708-.708L6.5 10.293l6.646-6.647a.5.5 0 0 1 .708 0z"/>
                            </svg> 200 contacts
                        </li>
                        <li class="mb-3">
                            <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-check2" viewBox="0 0 16 16">
                                <path d="M13.854 3.646a.5.5 0 0 1 0 .708l-7 7a.5.5 0 0 1-.708 0l-3.5-3.5a.5.5 0 1 1 .708-.708L6.5 10.293l6.646-6.647a.5.5 0 0 1 .708 0z"/>
                            </svg> 50% Discount
                        </li>
                    </ul>
                    <div class="d-grid gap-2">
                        <button class="btn btn-primary" type="button" onclick="CreateOrderID(1500, 200, '1500 INR - 200 Contacts')">Buy Now</button>
                    </div>
                </div>
            </div>
        </div>


    </div>
</div>

<script>
    var xhttp = new XMLHttpRequest();
    function CreateOrderID(amount, contactCounts, description) {
        totalAmount = amount*100;
        xhttp.open("GET", "/payment/createOrderId/"+totalAmount, false);
        xhttp.send();
        var razorpayOrderId = xhttp.responseText;
        console.log("razorpayOrderId" + razorpayOrderId);
        OpenCheckout(amount, contactCounts, razorpayOrderId, description);
    }
</script>

<script src="https://checkout.razorpay.com/v1/checkout.js"></script>
<script>
function OpenCheckout(amount, contactCounts, razorpayOrderId, description) {
    var options = {
        "key": "[[${rzp_key_id}]]", // Enter the Key ID generated from the Dashboard
        "amount": totalAmount.toString(), // Amount is in currency subunits. Default currency is INR. Hence, 50000 refers to 50000 paise
        "currency": "[[${rzp_currency}]]",
        "name": "[[${rzp_company_name}]]",
        "description": description,
        "image": "/assets/users/images/logo.png",
        "order_id": razorpayOrderId, //This is a sample Order ID. Pass the `id` obtained in the response of Step 1
        "callback_url": "/payment/success/"+amount+"/"+contactCounts+"/[[${rzp_company_name}]]/[[${rzp_currency}]]/"+description,
        "notes": {
            "description": description,
            "company_name": "[[${rzp_company_name}]]",
        },
        "theme": {
            "color": "#004A55"
        }
    };
    var rzp1 = new Razorpay(options);
    rzp1.on('payment.failed', function (response){
            console.log(response.error.code);
            console.log(response.error.description);
            console.log(response.error.source);
            console.log(response.error.step);
            console.log(response.error.reason);
            console.log(response.error.metadata.order_id);
            console.log(response.error.metadata.payment_id);
    });
    rzp1.open();
    e.preventDefault();
}
</script>

For above example we are using callback_url, so we need to implement payment success, where we will have razorpay_payment_id, razorpay_order_id, razorpay_signature, which we can store in database. Bellow is payment success controller example.
 @RequestMapping(value = {"/payment/success/{amount}/{contactCount}/{companyName}/{currency}/{description}"}, method = RequestMethod.POST)
    public String paymentSuccess(Model model,
                                 Authentication authentication,
                                 @RequestParam("razorpay_payment_id") String razorpayPaymentId,
                                 @RequestParam("razorpay_order_id") String razorpayOrderId,
                                 @RequestParam("razorpay_signature") String razorpaySignature,
                                 @PathVariable Float amount,
                                 @PathVariable Integer contactCount,
                                 @PathVariable String companyName,
                                 @PathVariable String currency,
                                 @PathVariable String description,
                                 RedirectAttributes redirectAttributes
    ){
        System.out.println("Save all data, which on success we get!");
        return "redirect:/payment";
    }

Thank you.