← back

Integrating Razorpay with Next.js

There are a lot of tutorials on how to integrate Razorpay with Next.js, but most of them are outdated. Let’s integrate Razorpay with Next.js 13 (app router).

0. Prerequisites

Install the Razorpay NPM package:

npm install razorpay

1. Create API Route

Create an API route in app/api/order/create/route.ts:

import { NextResponse } from "next/server";
import Razorpay from "razorpay";
import { v4 as uuid } from "uuid";

const instance = new Razorpay({
  key_id: process.env.RAZORPAY_KEY_ID,
  key_secret: process.env.RAZORPAY_KEY_SECRET,
});

export async function GET(request: Request) {
  const { searchParams } = new URL(request.url);
  const totalAmount = Number(searchParams.get("amount")); // in paisa

  const amount = totalAmount * 100;
  const options = {
    amount: amount.toString(),
    currency: "INR",
    receipt: uuid(),
  };

  const order = await instance.orders.create(options);
  return NextResponse.json({ message: "success", order });
}

Create one more route in app/api/order/verify/route.ts:

import { NextResponse } from "next/server";
import Razorpay from "razorpay";
import crypto from "crypto";
import Order from "@/models/OrderModel";
import { v4 as uuid } from "uuid";
import { connectDB } from "@/lib/mongodb";

const instance = new Razorpay({
  key_id: process.env.RAZORPAY_KEY_ID,
  key_secret: process.env.RAZORPAY_KEY_SECRET,
});

export async function POST(req, res) {
  const {
    razorpayOrderId,
    razorpaySignature,
    razorpayPaymentId,
    email,
  } = await req.json();
  const body = razorpayOrderId + "|" + razorpayPaymentId;

  const expectedSignature = crypto
    .createHmac("sha256", process.env.RAZORPAY_KEY_SECRET)
    .update(body.toString())
    .digest("hex");

  const isAuthentic = expectedSignature === razorpaySignature;

  if (!isAuthentic) {
    return NextResponse.json({ message: "invalid payment signature", error: true }, { status: 400 });
  }

  // connect db and update data
  await connectDB();
  await Order.findOneAndUpdate({ email: email },{ hasPaid: true });

  return NextResponse.json({ message: "payment success", error: false }, {  status: 200 });
}

2. Add Razorpay Script to Root Layout

Add the Razorpay script to the root layout in app/layout.tsx:

import Script from 'next/script'
import "./globals.css";

export default function RootLayout({ children }) {
  return (
    <>
      <html lang="en">
          <body>
            {children}
          </body>
      </html>
      <Script src="https://checkout.razorpay.com/v1/checkout.js" />
    </>
  );
}

3. Create Payment Button Component

Create a payment button component in app/components/PaymentButton.tsx:

"use client";
import React, { Suspense, useState } from "react";
import { useRouter } from "next/navigation";
import Loading from "@/app/loading";
import { useSession } from "next-auth/react";
import { Button, buttonVariants } from "@/components/ui/button";
import { cn } from "@/lib/utils";

const PaymentButton = ({ amount }) => {
  const { userData } = useSession();
  const router = useRouter();
  const [isLoading, setIsLoading] = useState(false);

  const makePayment = async () => {
    setIsLoading(true);

    // make an endpoint to get this key
    const key = "rzp_test_M******Pw5***n";
    const data = await fetch("/api/order/create?amount=" + amount);
    const { order } = await data?.json();
    const options = {
      key: key,
      name: userData.user?.email,
      currency: order.currency,
      amount: order.amount,
      order_id: order.id,
      modal: {
        ondismiss: function () {
          setIsLoading(false);
        },
      },
      handler: async function (response) {
        const data = await fetch("/api/order/verify", {
          method: "POST",
          body: JSON.stringify({
            razorpayPaymentId: response.razorpay_payment_id,
            razorpayOrderId: response.razorpay_order_id,
            razorpaySignature: response.razorpay_signature,
            email: userData.user?.email,
          }),
        });

        const res = await data.json();
        if (res?.error === false) {
          // redirect to success page
          router.push("/success");
        }
      },
      prefill: {
        email: userData.user?.email,
      },
    };

    const paymentObject = new window.Razorpay(options);
    paymentObject.open();

    paymentObject.on("payment.failed", function (response) {
      alert("Payment failed. Please try again.");
      setIsLoading(false);
    });
  };

  return (
    <>
      <Suspense fallback={<Loading />}>
        <div className="">
          <Button
            className={cn(buttonVariants({ size: "lg" }))}
            disabled={isLoading}
            onClick={makePayment()}
          >
            Pay Now
          </Button>
        </div>
      </Suspense>
    </>
  );
};

export default PaymentButton;

Success

That’s it! You have successfully integrated Razorpay with Next.js.

razorpay nextjs