Writing index
Field note / Frontend engineering

Integrating Razorpay payments in Next.js: a step-by-step guide

Set up checkout, verify signatures on the server, and handle webhooks safely when integrating Razorpay with Next.js.

1 min readnext.jspaymentsrazorpayserver
On this page
Integrating Razorpay payments in Next.js: a step-by-step guide

Payments are unforgiving: a single missing verification step is a security hole. The flow below keeps trust on the server and the browser as thin as possible.

Create the order on the server

Never let the client decide the amount.

export async function POST(request: Request) {
  const { planId } = await request.json();
  const plan = await getPlan(planId);
  if (!plan) return new Response("Unknown plan", { status: 400 });

  const order = await razorpay.orders.create({
    amount: plan.amountInPaise,
    currency: "INR",
    receipt: `receipt_${Date.now()}`,
  });

  return Response.json({ orderId: order.id, amount: order.amount });
}

The client receives an order id, not a price it can edit.

Open checkout on the client

const { orderId, amount } = await fetch("/api/payments/order", {
  method: "POST",
  body: JSON.stringify({ planId }),
}).then((res) => res.json());

const checkout = new Razorpay({
  key: process.env.NEXT_PUBLIC_RAZORPAY_KEY_ID,
  order_id: orderId,
  amount,
  handler: async (response) => {
    await fetch("/api/payments/verify", {
      method: "POST",
      body: JSON.stringify(response),
    });
  },
});

checkout.open();

Verify the signature server-side

This is the step that makes the payment trustworthy.

const expected = crypto
  .createHmac("sha256", process.env.RAZORPAY_KEY_SECRET!)
  .update(`${orderId}|${paymentId}`)
  .digest("hex");

if (expected !== signature) {
  return new Response("Invalid signature", { status: 400 });
}

Always handle webhooks

The browser can disappear between payment and callback. Webhooks are the source of truth.

  1. Verify the webhook signature
  2. Make the handler idempotent using the event id
  3. Fulfil the order from the webhook, not the client callback

Treat the client callback as a hint and the webhook as the fact.

Summary

Create orders on the server, verify every signature, and fulfil from webhooks. Everything else is presentation.

Continue reading

Related articles