Back to Blog
Payments

Implementing Secure Payments with Razorpay in Next.js

BiBimlesh Kumar
March 5, 2024
12 min read
Implementing Secure Payments with Razorpay in Next.js

Introduction to Razorpay and Next.js

Implementing a secure payment gateway is crucial for any e-commerce or SaaS application. In this comprehensive guide, we'll walk through integrating Razorpay with Next.js, focusing on security best practices and implementation details.

Why Choose Razorpay?

Razorpay offers several advantages for Indian businesses and international merchants:

  • Simple integration process
  • Support for multiple payment methods (cards, UPI, wallets, etc.)
  • Robust security features
  • Detailed analytics and reporting
  • Subscription and recurring payment support
  • Lower transaction fees compared to some alternatives

Setting Up Razorpay with Next.js

Step 1: Create a Razorpay Account

Start by signing up for a Razorpay account and completing the verification process. Once verified, you'll get access to your API keys from the Dashboard.

Step 2: Install Required Packages

Install the Razorpay checkout package:

npm install razorpay

Step 3: Set Up Environment Variables

Create a .env.local file in your Next.js project root and add your Razorpay API keys:


RAZORPAY_KEY_ID=your_key_id
RAZORPAY_KEY_SECRET=your_key_secret
      

Implementing the Payment Flow

Let's implement a complete payment flow with Razorpay and Next.js:

Step 1: Create an API Route for Order Creation


// pages/api/create-order.js
import Razorpay from 'razorpay';

export default async function handler(req, res) {
  if (req.method !== 'POST') {
    return res.status(405).json({ message: 'Method not allowed' });
  }

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

    const { amount, currency = 'INR', receipt, notes } = req.body;

    const options = {
      amount: amount * 100, // Razorpay expects amount in paise
      currency,
      receipt,
      notes,
    };

    const order = await razorpay.orders.create(options);
    return res.status(200).json(order);
  } catch (error) {
    console.error(error);
    return res.status(500).json({ message: 'Something went wrong', error: error.message });
  }
}
      

Step 2: Create a Payment Component


// components/PaymentButton.js
import { useState } from 'react';
import Script from 'next/script';

export default function PaymentButton({ amount, productName, customerName, customerEmail }) {
  const [loading, setLoading] = useState(false);

  const makePayment = async () => {
    setLoading(true);
    try {
      // Create order on the server
      const response = await fetch('/api/create-order', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          amount,
          receipt: 'order_' + Date.now(),
          notes: {
            productName,
            customerName,
            customerEmail,
          },
        }),
      });

      const order = await response.json();

      if (!response.ok) {
        throw new Error(order.message || 'Failed to create order');
      }

      // Initialize Razorpay payment
      const options = {
        key: process.env.NEXT_PUBLIC_RAZORPAY_KEY_ID,
        amount: order.amount,
        currency: order.currency,
        name: 'Your Company Name',
        description: productName,
        order_id: order.id,
        handler: function (response) {
          // Handle successful payment
          verifyPayment(response);
        },
        prefill: {
          name: customerName,
          email: customerEmail,
        },
        theme: {
          color: '#3399cc',
        },
      };

      const paymentObject = new window.Razorpay(options);
      paymentObject.open();
    } catch (error) {
      console.error('Payment error:', error);
      alert('Payment failed: ' + error.message);
    } finally {
      setLoading(false);
    }
  };

  const verifyPayment = async (paymentResponse) => {
    try {
      const response = await fetch('/api/verify-payment', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(paymentResponse),
      });

      const data = await response.json();

      if (response.ok) {
        alert('Payment successful!');
        // Redirect to success page or update UI
      } else {
        throw new Error(data.message || 'Payment verification failed');
      }
    } catch (error) {
      console.error('Verification error:', error);
      alert('Payment verification failed: ' + error.message);
    }
  };

  return (
    <>