49 automated assertions passing

Razorpay payments for Next.js that actually verify the payment.

Server-side orders, HMAC-verified webhooks, idempotent fulfilment and refunds — for Next.js 14 (Pages Router). Built for the India-first stack, not another Stripe tutorial with the names swapped.

Buy now — ₹1500

UPI · Cards · Netbanking  ·  One-time purchase. Instant download. Free updates. Test-mode ready.

The three bugs I found in every Razorpay integration I reviewed

I wrote this kit after reading through several. The same three mistakes showed up almost every time.

1

The price comes from the client

The browser POSTs { amount: 500 } and the server trusts it. Anyone opens devtools, changes it to 1, and buys your ₹5000 product for ₹1. Here the client sends only a product id — the server looks up the real amount.

2

The webhook is trusted without verification

An unverified webhook lets anyone who guesses the URL POST a fake payment.captured and get free product. Every request here is checked against x-razorpay-signature over the raw body before a byte of payload is trusted.

3

Webhooks are assumed to arrive exactly once

Razorpay retries. Without an atomic guard you double-fulfil — you ship twice and get paid once. Fulfilment here goes through a check-and-set that returns true for exactly one delivery per order.

The part everyone gets wrong

Webhook signature verification needs the request's raw bytes. Re-serialising JSON changes key ordering and whitespace, so the signature can never match — and the only error you get is "invalid signature", with no hint why.

// The body parser must be OFF — the signature covers the raw bytes.
// If you `JSON.parse` first and re-serialise, this never matches.
export const config = { api: { bodyParser: false } };

const rawBody = await readRawBody(req);              // raw stream

const valid = verifyWebhookSignature(
  rawBody,
  req.headers["x-razorpay-signature"]            // timing-safe HMAC
);
if (!valid) return res.status(400).json({ error: "Invalid signature." });

// Only NOW is the payload trustworthy.
const event = JSON.parse(rawBody.toString("utf8"));

// Atomic: true for exactly ONE delivery per order.
const { claimed } = await orderStore.claimForFulfilment(orderId, paymentId);
if (!claimed) return res.status(200).json({ duplicate: true });   // not 500!

What's in the download

Verified, not just written

Before release I drove the real webhook handler with mock requests. These are actual results, not marketing claims.

TestResult
Valid checkout signature acceptedPASS
Signature for a different order or payment rejectedPASS
Signature computed with the wrong secret rejectedPASS
Tampered, unsigned and reordered-body webhooks rejectedPASS
Duplicate deliveries do not re-fulfilPASS
5 concurrent deliveries → exactly 1 fulfilmentPASS
Late payment.failed cannot downgrade a paid orderPASS
Duplicate refund events are a no-opPASS
TypeScript compiles under strict: truePASS

49 assertions, all passing. 17 on signature verification, 32 on the webhook handler.

Pricing

One-time. No subscription. Free updates to whatever you buy.

₹1500 one-time

Everything included. No tiers, no upsell.

Buy now — ₹1500

Payment: secure Razorpay checkout — UPI, cards, netbanking and wallets. Your download is emailed to the address you provide at checkout.

Want to see the code first? The core of it is free and MIT licensed on GitHub — browse the repo.

Pages Router, not App Router. This is built on pages/ and pages/api/ for Next.js 14. There is no App Router version yet — if you specifically need app/, don't buy this.

Questions

Is this Pages Router or App Router?

Pages Router. It's built on pages/ and pages/api/. There is no App Router version.

Do I need a database?

No. It ships with a JSON order store behind a six-method interface. For production multi-instance hosting, swap it for Postgres by editing one file.

Is it really tested?

Yes. 49 assertions run against the real webhook and signature handlers — 17 on signature verification, 32 on the webhook handler. TypeScript compiles clean under strict: true.

What about refunds?

Full and partial refunds are supported through an authenticated endpoint that checks the refundable balance first.

Can I use it for a client project?

Licensed for one commercial project. If you need it for multiple client projects, email support@nethercore.in and we'll sort something out.

Do I need business verification to try it?

No. Razorpay test mode works without business verification. You only need a verified account to accept live payments.