Site index
Arrow keys to navigateEnter to open / Esc to close
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

Modal interface

Accent system

Choose a palette. The selection is saved on this device.

Accent color themes

28 palettes available

Modal interface

A note worth keeping

A randomly selected thought from the inspiration archive.