DEV Community

Cover image for How to Integrate RazorPay in Next.js 14/15 with Easy Steps.
Kush Chaudhary
Kush Chaudhary

Posted on

How to Integrate RazorPay in Next.js 14/15 with Easy Steps.

Alright, let’s make this super simple! If you’re working on a Next.js project and need to integrate Razorpay for payments, just follow these steps, copy-paste the code, and you’re done. No fluff, just what you need

Step 1: Install Required Packages

First, install the Razorpay Node.js SDK and other necessary packages. In your project directory, run:

npm install razorpay @types/razorpay axios
Enter fullscreen mode Exit fullscreen mode

Step 2: Get API Keys from Razorpay

Get api keys from here
Image description

Store your Razorpay keys in a .env file at the root of your project

NEXT_PUBLIC_RAZORPAY_KEY_ID = YOUR_RAZORPAY_KEY_ID
RAZORPAY_KEY_ID = YOUR_RAZORPAY_KEY_ID
RAZORPAY_KEY_SECRET = YOUR_RAZORPAY_KEY_SECRET
Enter fullscreen mode Exit fullscreen mode

Step 4: Create an Order API Route

Next.js has a built-in API route system, making it easy to handle backend logic. Let’s create an API route for Razorpay to generate orders.

Create a new API route /api/createOrder/route.ts

import { NextRequest, NextResponse } from "next/server";
import Razorpay from "razorpay";

const key_id = process.env.RAZORPAY_KEY_ID as string;
const key_secret = process.env.RAZORPAY_KEY_SECRET as string;

if (!key_id || !key_secret) {
    throw new Error("Razorpay keys are missing");
}

const razorpay = new Razorpay({
    key_id,
    key_secret
})

export type OrderBody = {
    amount: number;
    currency: string;
}

export async function POST(request: NextRequest) {
    try {

        const { amount, currency }: OrderBody = await request.json();
        if (!amount) {
            return NextResponse.json({ message: `Amount is required` }, { status: 400 })
        }

        const options = {
            amount,
            currency: currency || "INR",
            receipt: `receipt#${Date.now()}`,
        }

        const order = await razorpay.orders.create(options);
        console.log("Order Created Successfully");

        return NextResponse.json({ orderId: order.id }, { status: 200 })

    } catch (error) {
        return NextResponse.json({ message: "Server Error", error }, { status: 500 })
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 5: Create a function for generating OrderId

import axios from "axios";

export async function createOrderId(amount: number, currency: string) {
    try {
        const response = await axios.post("/api/createOrder", {
            amount: amount * 100, // Convert to paise
            currency: "INR",
        });

        console.log("Order Response:", response.data);
        return response.data.orderId;
    } catch (error) {
        console.error(error);
        throw new Error("Failed to create order");
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 6: Create a Checkout Button

Create a reusable component /components/BuyButton.tsx for the Razorpay checkout button. Copy the below code:

"use client";

import axios from "axios";
import React from "react";
import Script from "next/script";
import { createOrderId } from "@/utils/createOrderId";

export default function PurchaseButton() {
  const [isLoading, setIsLoading] = React.useState(false);

  const handlePayment = async () => {
    setIsLoading(true);
    const price = 100; // Replace with dynamic price
    try {
      const orderId: string = await createOrderId(price, "INR");
      const options = {
        key: process.env.NEXT_PUBLIC_RAZORPAY_KEY_ID,
        amount: price * 100,
        currency: "INR",
        name: "YOUR_COMPANY_NAME", // Replace with dynamic company name
        description: "Payment for your order", // Replace with dynamic order description
        order_id: orderId,
        handler: async function (response: any) {
          try {
            const paymentResponse = await axios.post("/api/verifyOrder", {
              razorpay_order_id: orderId,
              razorpay_payment_id: response.razorpay_payment_id,
              razorpay_signature: response.razorpay_signature,
            });

            alert("Payment Successful!");
            console.log(paymentResponse.data);
          } catch (error) {
            alert("Payment verification failed. Please contact support.");
            console.error(error);
          }
        },
        prefill: {
          name: "YOUR_NAME", // Replace with dynamic user data
          email: "YOUR_EMAIL", // Replace with dynamic user data
        },
        theme: {
          color: "#3399cc",
        },
      };

      const razorpay = new (window as any).Razorpay(options);
      razorpay.on("payment.failed", function (response: any) {
        alert("Payment failed");
        console.error(response.error);
      });
      razorpay.open();
    } catch (error) {
      alert("Payment failed. Please try again.");
      console.error(error);
    } finally {
      setIsLoading(false);
    }
  };

  return (
    <>
      <button
        className="bg-emerald-700 text-white font-semibold px-4 py-2 rounded-xl hover:bg-emerald-600 transition-all duration-300 hover:shadow-lg hover:scale-105"
        onClick={handlePayment}
        disabled={isLoading}
      >
        {isLoading ? "Processing..." : "Buy Now"}
      </button>
      <Script
        id="razorpay-checkout-js"
        src="https://checkout.razorpay.com/v1/checkout.js"
      />
    </>
  );
}

Enter fullscreen mode Exit fullscreen mode

Step 8: Verify Payment

For added security, you can verify the payment signature server-side. Create a new API route /api/verifyOrder/route.ts

import { NextRequest, NextResponse } from "next/server";
import crypto from "crypto";

export interface VerifyBody {
    razorpay_order_id: string;
    razorpay_payment_id: string;
    razorpay_signature: string
};

export async function POST(request: NextRequest) {
    try {
        const { razorpay_order_id, razorpay_payment_id, razorpay_signature }: VerifyBody = await request.json();

        if (!razorpay_order_id || !razorpay_payment_id || !razorpay_signature) {
            return NextResponse.json({ error: "Missing required parameters", success: false }, { status: 400 })
        }

        const secret = process.env.RAZORPAY_KEY_SECRET as string
        if (!secret) { return NextResponse.json({ error: "Razorpay secret not found" }, { status: 400 }) }

        const HMAC = crypto.createHmac("sha256", secret)
        HMAC.update(`${razorpay_order_id}|${razorpay_payment_id}`)
        const generatedSignature = HMAC.digest("hex")

        if (generatedSignature === razorpay_signature) {
            return NextResponse.json({ message: "Payment verified successfully", success: true })
        } else {
            return NextResponse.json({ error: "Invalid signature", success: false }, { status: 400 })
        }
    } catch (error) {
        return NextResponse.json({ error: "An error occurred", success: false }, { status: 500 })
    }
}
Enter fullscreen mode Exit fullscreen mode

Here is how you might create a products page and add checkout flow:
checkout this Github repository where I have created complete payment flow on a products page: github/hanuchaudhary/RazorpayIntegration

Done!

That’s it! You’ve:

  • Installed the required dependencies.
  • Added Razorpay keys to .env.
  • Created two POST API routes: /api/createOrder/route.ts and /api/verifyOrder/route.ts.
  • Built a reusable button component.
  • Added the Razorpay script. For extra features like webhooks or subscriptions, check out the Razorpay Documentation.

Conclusion

Integrating Razorpay with Next.js 14/15 is straightforward and efficient. By following these steps, you can securely accept payments in your application. For advanced features like subscriptions or webhooks, refer to the Razorpay Documentation.

Thanks for reading this blog! Don’t forget to leave a comment💬!

Top comments (0)