Razorpay MERN ecommerce viva — payment verification and order flow
HMAC signature verification, test-mode keys, order state after payment, and catalogue admin — the ecommerce payment story examiners grill hardest.
Rajan
Founder & kit engineer
Payment integration is high risk in vivas — either you explain HMAC verification clearly, or the panel assumes you pasted a tutorial. Razorpay returns order_id, payment_id, and signature to the client; your server must verify the signature before marking an order paid. Never update order status from a client callback alone. That single rule is the difference between a defensible ecommerce project and a demo that collapses under one question.
This post is a viva-oriented walkthrough of checkout, verification, test mode, cart architecture, admin flows, and the questions Indian B.Tech / BCA / MCA panels actually ask. Use it with the MERN ecommerce kit. For stack-choice context when someone asks “why not an AI project?”, keep AI vs MERN for final year handy. Compare payment complexity with a non-payment MERN system like library management when the examiner asks what made ecommerce harder.
Why payments scare students (and how to stay calm)
Razorpay looks like “just open a modal.” The academic substance is trust boundaries: the browser is hostile; amounts and paid flags must be decided on the server; secrets stay in environment variables; test keys never become live keys in a submitted zip. If you can narrate that boundary while the modal runs, you sound like an engineer, not a UI clicker.
What “good” looks like in five minutes
Add a product to cart → checkout → server creates Razorpay order → modal opens with test keys → success → client POSTs ids + signature → server verifies → order history shows paid. Optionally fail once with a test failure card and show the order stays pending. That failure path is memorable and honest.
Checkout flow end to end
1. Cart to order intent
User reviews cart. Client sends product ids and quantities only — not a final price the client invented. Server loads products from MongoDB, recomputes line totals and grand total in paise, and creates an Order document in pending (or equivalent) with a price snapshot of each line item.
2. Create Razorpay order on the server
Server calls Razorpay with the computed amount (paise), currency INR, and a receipt/reference tied to your Order _id. Store the Razorpay order_id on your Order. Return to the client: Razorpay key_id (public), order_id, amount, and any prefill fields you allow.
3. Client opens checkout
Razorpay Checkout modal uses key_id + order_id. User pays with test UPI/card. On success, Razorpay gives the client payment_id, order_id, and signature.
4. Verify on your API
Client POSTs those three values (plus your internal order id if needed) to /api/payments/verify (name yours consistently). Server recomputes expected signature and only then sets order paid, decrements stock if not already reserved, and returns confirmation.
5. Show history
Order history page reads from MongoDB — not from Razorpay as source of truth for your UI. Razorpay is the payment rail; your Order collection is the business record.
HMAC verification (draw this on the board)
The formula
Expected signature = HMAC-SHA256 of order_id + "|" + payment_id using your key secret. Compare with the signature Razorpay sent.
Constant-time compare
Use a timing-safe comparison (for example Node’s crypto.timingSafeEqual on buffers) so you do not leak information through early exits. Mentioning this in viva shows you read past the happy-path blog post.
Only then mark paid
If signatures differ → 400, leave order pending/failed path. If order already paid → idempotent success (see below). Never trust handler success in the browser as authorization to mutate stock.
Whiteboard script
Boxes: Browser → Verify API → HMAC check → Update Order + Inventory. Cross out an arrow that goes “Browser success → mark paid directly.” Say: “That crossed arrow is the vulnerability.”
Never trust the client amount
Attack version of your app: user edits JavaScript and pays ₹1 for a ₹10,000 item. Defense: server recomputes from product documents and quantities. Client may display price for UX; server decides charge amount when creating the Razorpay order. Stock and price snapshots freeze at purchase time so later catalog price changes do not rewrite history.
Test mode without real money
Keys and .env
Razorpay test key_id / key_secret in .env. Ship .env.example with placeholders. Never commit live secrets. In viva: “Secrets are environment variables, not in git.”
Demo cards and UPI
Use Razorpay’s documented test instruments. Practice one success and one failure. Failure proves you did not only screenshot the green path.
Live keys on college Wi-Fi
Do not. External examiners sometimes ask whether the demo is test mode — answer yes, proudly. Real money on a student laptop is a liability, not a flex.
Order states you should be able to recite
A clean student model:
- ▸pending — created, awaiting payment
- ▸paid — signature verified
- ▸shipped — admin advanced
- ▸delivered — complete
- ▸cancelled / failed — payment never completed or order voided; inventory restored if you decremented early
Be explicit about when stock decrements: at paid time (simpler for many kits) or at order creation with reservation (harder; explain rollback). Pick one and document it.
Webhook vs client callback
What panels want to hear
Client callback gives immediate UX after the modal. It can fail if the user closes the tab before your verify POST. Webhooks are the production reliability path: Razorpay notifies your server server-to-server. Many academic demos verify via client callback + HMAC; that is acceptable if you state: “Production would add webhook handlers for reconciliation.”
Do not pretend you built webhooks
If code has no webhook route, say so. Examiners prefer an honest gap over a fake architecture slide.
Idempotency and double payment
Q: What if verify is called twice?
A: If order already paid, return success without charging again or double-decrementing stock. Razorpay order creation should also be tied so you do not spawn duplicate unpaid chaos for the same checkout intent — store and reuse the Razorpay order id for that Order document.
Cart architecture (Redux and persistence)
Why Redux Toolkit appears in ecommerce kits
Cart is cross-route UI state: product page, cart page, header badge. Redux (or equivalent) keeps that coherent. Explain: cart in client state until checkout creates a server Order; you are not writing every quantity click to MongoDB.
localStorage optional
Persisting cart across refresh is UX polish. On login, merge guest cart carefully to avoid duplicates — if you did not implement merge, say guest cart is session-only.
Snapshot line items
When creating the Order, copy product name, unit price, quantity into the order. Later catalog edits must not rewrite past invoices.
Cloudinary (or image URL) flow
Admin uploads image → Multer temp file → Cloudinary SDK → store HTTPS URL on product document. Do not dump binary into MongoDB. Viva line: “Metadata in MongoDB, blobs in object storage.” If you use static URLs without Cloudinary, say that too — consistency beats buzzwords.
Admin features worth demoing
- ▸Product CRUD with image and stock
- ▸Order list with status badges
- ▸Mark shipped / delivered
- ▸Optional: simple search (MongoDB text index or careful regex — know which)
Admin demo path
Login admin → add product → logout → customer purchases → admin marks shipped. Full lifecycle in one story. Compare with non-payment admin flows in library management if asked how ecommerce differs: money + inventory + external API trust.
Inventory and failure paths
If you decrement stock on pay: verification success and stock update should be consistent (same request handler, careful error handling). If payment fails after a mistaken decrement, restore quantity — walk that path in code during viva if you implemented it. If stock only decrements after verify, say “failed payments never touch inventory.”
Failed payment UX
User sees retry; order remains pending; cart may remain. Demo a failed test card once. Panels remember students who show recovery.
Refunds: scope discipline
Refunds via Razorpay API, partial refunds, and settlement reports are easy scope creep. Prefer: “Out of scope; future work via Razorpay refund API; admin may flag dispute manually.” Do not show a Refund button that only toggles a boolean unless you explain it is not a real PSP refund.
Security questions to prepare
Where is the secret? Environment variable on the server; never shipped to the browser (only key_id is public).
HTTPS? Required for real deployments with JWT and payments; local demo may be HTTP — state production would enforce HTTPS.
CORS / cookies? Explain how your auth token is stored and why APIs reject cross-origin abuse according to your setup.
CSRF? If you use cookie sessions, discuss protections; if Authorization bearer tokens from localStorage, explain the tradeoff honestly.
Can I mark paid from DevTools? Without a valid signature, verify endpoint rejects — that is the point of HMAC.
Ecommerce scope: what to ship vs defer
Ship: catalog, cart, checkout, verify, order history, admin product CRUD, test-mode demo.
Defer with one-line future-work notes: wishlist, reviews, coupons, recommendations, COD, wallets beyond what you tested, multi-vendor marketplace. Half-built coupon UIs hurt demos more than honest “not implemented” answers.
Razorpay verification alone is enough complexity for an external examiner if the story is crisp and the test payment works on the presentation laptop.
Product search (if present)
If the search bar uses a MongoDB text index, say so. If it is client filter or regex, say so. Do not claim “Elasticsearch” or “Atlas Search” unless configured. Wrong vocabulary is a classic viva failure mode.
PDF invoices and extras
PDF invoice generation is optional stretch. If missing, future work. Order history with status badges is enough for most rubrics.
COD vs online payment
If you only built Razorpay, state COD out of scope. Otherwise examiners invent cash-drawer questions you did not design for.
Sample viva Q&A pack
Walk through payment after the modal closes. Client sends payment_id, order_id, signature; server HMAC; then paid.
Why paise? Razorpay amounts are integer subunits; floating rupees cause rounding bugs.
What is in the order document? User id, line snapshots, amounts, Razorpay order id, status timestamps.
Webhook? Not in demo / planned for production — be consistent with code.
Double submit? Idempotent verify.
Secret in GitHub? Never; rotate if leaked; use .env.
Why MERN? Full-stack ownership of UI + API + DB; payment logic lives in Node where secrets belong. See also stack framing in AI vs MERN.
Report mapping
Chapter 3: customer vs admin use cases; payment sequence diagram.
Chapter 4: Order and Product schemas; cart vs order distinction.
Chapter 5: Razorpay integration subsection with verify pseudocode.
Chapter 6: test cases — success pay, bad signature rejected, stock after pay, admin ship.
Limitations: test mode only, no webhook, no refunds API.
Pitfalls
- ▸Marking paid in the frontend
- ▸Trusting client price
- ▸Live keys in submission
- ▸No failure demo
- ▸Claiming webhooks/refunds you did not build
- ▸Feature creep (wishlist + coupons + AI recommendations) with a broken checkout
Pre-viva checklist
- ▸[ ] Test keys load from
.envon presentation machine - ▸[ ] Success payment rehearsed offline as far as network allows
- ▸[ ] Bad signature / failed pay path known
- ▸[ ] Board sketch of HMAC ready
- ▸[ ] Admin add-product path works with image
- ▸[ ] Abstract does not claim COD/webhooks/refunds falsely
- ▸[ ]
.envnot in zip;.env.exampleis
Sequence diagram you should be able to redraw
Without looking at notes, redraw:
- ▸Browser → API: create order (productIds, qtys)
- ▸API → MongoDB: load products, compute paise, insert Order pending
- ▸API → Razorpay: create order
- ▸API → Browser: key_id + razorpay order_id
- ▸Browser → Razorpay Checkout
- ▸Browser → API: payment_id, order_id, signature
- ▸API: HMAC verify → update Order paid → adjust stock
- ▸Browser: order history
If you can redraw this in sixty seconds, HMAC questions become easy. Practice on paper the night before — not during the viva.
Amount edge cases worth one sentence each
Zero quantity rejected. Quantity above stock rejected before Razorpay order creation. Currency fixed to INR for the academic demo. Discount coupons out of scope unless implemented end-to-end with server-side recalculation — a client-only coupon field is a viva trap.
What “order snapshot” prevents
Admin changes product price after you paid. Your Order line still shows the price you were charged. That is intentional. Explain it as historical integrity, same idea as invoice immutability in larger systems.
Deployment talking points (honest, short)
If you deployed to Render/Railway/Vercel-style hosting, mention HTTPS and env vars there. If not, say local demo with production deployment as future work — do not invent a Kubernetes slide. Payment secrets on a free tier deserve rotation discipline: revoke test keys if you ever pasted them in a screenshot that went to WhatsApp groups.
Comparing complexity to other MERN kits
Library issue/return is authorization-heavy without money. Hotel booking is availability-heavy without PSP signatures. Ecommerce adds a third-party trust boundary. Use that sentence when asked “why is this harder than a CRUD portal?”
Related reading
Alongside AI vs MERN, review common viva mistakes so payment confidence does not turn into overclaiming.
Project kits
- ▸MERN E-Commerce — Razorpay checkout, verify flow, Redux cart, admin catalogue.
- ▸Library Management System — MERN without payments, useful contrast for “what was complex?”
- ▸Hotel Booking System — another transactional MERN domain if you need a second non-payment comparison.
Takeaway: Draw the Razorpay verify flow on the board and never trust client-side payment success alone. Use test keys, freeze prices on the server, and keep the ecommerce kit’s verify endpoint as the single gate between “modal said OK” and “order is paid.”
Ready to work on your own project?
We build complete project kits with source code, report, slides, and viva prep — message us on WhatsApp to get started.
Ask about this on WhatsApp