Logo Loading Please Wait...

How to Integrate a Payment Gateway in India: A Step-by-Step Guide

How to Integrate a Payment Gateway in India: A Step-by-Step Guide
24 March 2026

You’ve built the product. The design is clean, the features work, and the backend handles everything it needs to. Then the question hits—how do users actually pay?

In India in 2026, it’s mostly straightforward. Razorpay, PayU, and Cashfree have made payment gateway integration accessible to any developer who can read a REST API. What goes wrong isn’t usually the integration itself — it’s the corners people cut. A missed verification step, no webhook handler, and real transactions start falling through with no way to recover them.

This guide walks you through a production-ready integration using Razorpay with Node.js and React. The same logic applies to Flutter and Laravel; the steps are just expressed differently.

1. Pick the Right Gateway for Your Project

India’s payment ecosystem is unique. UPI, net banking, wallets, EMI, and cards all coexist — and your gateway needs to handle the full mix.

The four options most developers use:

  • Razorpay — the best starting point for almost every new project; developer-friendly, fast onboarding, comprehensive Indian payment method support, and the clearest documentation available
  • PayU — been around the longest and carries the most institutional trust; the right choice for enterprise builds, but the onboarding process takes more time
  • Cashfree — the strongest option if your platform involves split payments or payouts to multiple parties; marketplaces and gig economy apps do well here
  • PhonePe Payment Gateway — a newer but growing option backed by a huge UPI user base; particularly useful for apps targeting smaller cities and towns

For a React and Node.js stack, start with Razorpay. You’ll reach a working test transaction faster than with any other option.

2. Get Your Prerequisites Sorted

Jumping into code without the basics in place wastes time. Get these done first.

What you need before you begin:

  • A Razorpay account — test keys are available on sign-up; live keys need KYC, which usually clears in a day or two
  • Node.js v18 or above — with npm and a working Express.js server already running
  • A React frontend — Vite or Create React App both work fine
  • Your Key ID and Key Secret — pull these from Dashboard → Settings → API Keys; the Key Secret goes only on the server, never near the frontend
  • Environment variables — load credentials from a .env file; hardcoding them is a shortcut that creates real problems

Security built in from the start is always cheaper than security bolted on after something goes wrong.

3. Create the Order Server-Side

Every Razorpay payment starts with an Order object your backend creates. That Order locks in the amount and currency before the frontend is involved — meaning no one can tamper with the price in the browser.

Install the SDK with npm install razorpay, initialise it with your environment variables, then create a POST endpoint at /create-order that takes the amount and calls razorpay.orders.create() with the options object.

The detail that catches most developers: Razorpay accepts amounts in paise, not rupees. ₹499 becomes 49900. The endpoint returns an order ID — that’s what gets passed to the React checkout.

4. Open the Payment Modal in React

Backend order created. Now the frontend needs to load the Razorpay checkout and hand control over to the payment modal when the user clicks pay.

How it works on the React side:

  • Load the checkout script on demand — inject it dynamically into the document rather than including it on every page; keeps your bundle clean and load times fast
  • Fetch the order from your backend — call your /create-order endpoint with the purchase amount and pass the returned order ID into the Razorpay options object
  • Define your handler function — this fires when Razorpay marks the payment as authorised; it gives you three values back: razorpay_order_id, razorpay_payment_id, and razorpay_signature
  • Pass those three values to your server — immediately; do not update your order status in the browser; nothing gets marked as paid until the backend says so
  • Prefill name, email, and phone — reduces drop-off at checkout more than most developers expect

The handler fires on authorization. Authorization is not the same as confirmed payment. The signature verification step is what closes that gap.

5. Verify the Payment Signature on the Backend

Most tutorials skip this. It’s the most important security step in the entire integration.

Razorpay signs every payment response with HMAC SHA256 using your Key Secret. Your server generates the same hash and compares. Match means real — mismatch means something is wrong.

The logic:

  • Concatenate the order ID and payment ID — joined with a pipe character; the string looks like order_id|payment_id
  • Generate the HMAC hash — use Node’s native crypto module with createHmac, sha256 algorithm, and your Key Secret
  • Compare signatures — if yours matches what Razorpay sent, write the confirmed status to your database
  • If they don’t match — reject the request and log it before doing anything else

Never mark an order paid from the frontend. Only from here.

6. Add Webhook Handling — Don’t Skip This

Everything above covers the happy path. Webhooks cover everything else — dropped connections, closed tabs, network timeouts, and the other real-world scenarios that happen every day in production.

In Razorpay Dashboard → Settings → Webhooks, point to your endpoint and subscribe to payment.captured, payment.failed, and order.paid.

What a solid webhook handler does:

  • It runs server-to-server — independent of the user’s browser; fires whether they stay on the page or not
  • Verify the signature — Razorpay attaches an x-razorpay-signature header; validate it the same way you validate payment signatures
  • Use express.raw — not express.json; the raw buffer is required for the hash to generate correctly
  • Handle duplicates — Razorpay can send the same event more than once; check whether the order is already paid before processing it again

Together they leave no gaps. On their own, either one does.

Test It Properly Before You Go Live

Razorpay test mode covers everything — dummy cards, test UPI IDs, simulated wallet flows. Card number 4111 1111 1111 1111, any future expiry, any CVV, OTP 1234 gives you a successful payment.

Don’t just test the happy path. Test a failed payment, a late webhook, and a closed tab mid-checkout. If your integration handles all three cleanly, it’s ready.

The difference between a quick integration and a reliable one is a few hours of work. Signature verification, webhook handling, and edge case coverage aren’t advanced topics — they’re what production-grade integration actually looks like.If your business needs a payment-integrated app or platform built on React, Node.js, or Flutter, get in touch with AllUpNext. We’ve been delivering production software for businesses across India and Australia for over 13 years.