Home

The checkout India actually buys through.

UPI, COD, GST and WhatsApp are first-class here, not apps bolted onto a card-first, Western flow. One mobile number, one OTP, the address prefilled from the last order. And every rupee settles to your own Razorpay, with zero platform fee.

₹0 platform feeCOD proven server-sideGST extracted from the MRP
Checkout2 items · ₹649
Mobile number
+91 98••• ••210Verified
Email optional — updates go by WhatsApp
Deliver to
Pay by
Review

The mobile number is the first field, and the only one that's required.

India buys by phone: orders update over WhatsApp and SMS, and email is only for the invoice. So the checkout asks for one number, not two, and never stands an email wall in the way.

The card-first checkoutbuilt elsewhere
Email address
Required — the wall before anything else
Contact phone
Field one of two
Recipient phone
The same number, typed again

Three fields, two of them the same number, and an email wall, all before a shopper who buys by phone has done anything.

Phone-first, hereOne field
Mobile number+91 98••• ••210
The first field — and the only phone box
Email addressoptional
Optional, below — for the invoice only

The contact and shipping phone are collapsed into a single mobile field. Email drops below, optional. India buys by phone, and order updates ride WhatsApp and SMS.

One OTP, and a returning shopper's address fills itself in.

A returning guest verifies their number and their last delivery address appears inline, with no login round-trip and no retyping. And because the number is read from the verified token, not the form, no stranger can type it to read someone's address.

Returning? Verify to prefill
+91 98••• ••210
Waiting for the OTP
POST /api/checkout/prefill
Reads the phone from the verified OTP token — never the request body
Looks up that number's own last-order address
Returns it inline — no login, no IDOR, no phone-enumeration

Identity is revealed only after the OTP. A stranger can never type your number to read your address. And that one verified number then satisfies COD too, so no one verifies twice.

The address starts with a tap, not an empty form.

Use my location, then search, then a dropped pin — typing is the last resort. The address form is where mobile checkouts leak, so it's the part we made effortless.

Add a delivery address
Use my location
One tap, the default. Renders a button, never auto-prompts.
01
Search address
Type a landmark, pick the match.
02
Drop a pin
Move the map to the exact door.
03
Type it all out — the last resort, not the first ask.

A form full of empty boxes is where mobile checkouts die. So the address starts with one tap: location first, search second, a dropped pin third. Typing is the fallback, never the opening move.

And when it geocodes

Reverse-geocoding runs on a server-side key and logs the provider’s real status. A rejected or quota’d key surfaces as an error. It can never quietly masquerade as “no address found” and lose you the order.

COD is proven on the server. It was never just a checkbox.

Cash on delivery is where fraud and returns hide, so a cash order ships only after the number is proven server-side, and the shopper gets a gentle nudge toward prepaid instead of a lecture.

A cash order ships only after the number is proven
A logged-in customer whose account phone equals the order phone
Accepted
A fresh Firebase OTP token whose phone equals the order phone — re-verified server-side
Accepted
The client’s cod_phone_verified flag
A UX hint — never trusted

The proving phone always comes from the session or the token, never the request body. High-risk cash orders route to a confirmation queue before a label ever prints.

Cash on delivery+ ₹49
Pay online now and save ₹49 — free delivery on prepaid.
One tap converts to prepaid, and prepaid returns less often.

When a cash order would trip the under-threshold delivery fee, the shopper is offered the swap, not scolded for choosing COD. Lower fee for them, lower return risk for you.

Store credit spends exactly once — even from two tabs at the same instant.

Wallet balance is real money, so it's redeemed like a bank ledger, not a subtracted number on a page: one atomic, row-locked, idempotent transaction. Reserved when the order is created, swept back if payment fails.

Wallet · ₹150 available
Sample data
Tab A
Redeem ₹150
fires at 12:04:01.220
Tab B
Redeem ₹150
fires at 12:04:01.221
SECURITY DEFINER redeem RPC
row-locked · idempotent per order
₹150 applied
once, atomically
Second attempt no-ops
same order, idempotent

Store credit is real money, so spending it is treated like a bank ledger, not a subtracted number on a page. Two tabs, a double-tap, a flaky network retry: the credit still leaves the wallet exactly once.

  • Redemption is a single row-locked, idempotent transaction. No double-spend.
  • Reserved when the order is created, swept back if payment fails.
  • Prepaid only — credit rides UPI, cards and netbanking, never COD.

GST comes out of the price. It's never bolted on at the end.

The price you set is final. Tax is extracted from it at 5% for packaged tea, the India-correct model most Western checkouts get backwards. Business buyers get a proper GSTIN invoice, and every transaction settles to your own Razorpay.

The price you set is the price they payWorked example
MRP₹649.00
Taxable base
GST
Taxable base₹618.10
GST at 5% · HSN 0902.30₹30.90
GST = round(MRP × 5 ÷ 105)

Extracted from the price, never added on top. That’s the model most Western checkouts get backwards. Every amount is computed in paise, so the taxable base always reconciles.

Your own Razorpay — zero platform fee
UPI, cards and netbanking settle straight to your account. We never take a cut of a transaction, ever.
GSTIN capture for B2B invoices
A strictly validated 15-character GSTIN on the order produces a proper business tax invoice.
Sequential GST invoice series
FY-scoped numbering like ZT/26-27/0001, with the extracted GST and a link emailed to the buyer.

The browser suggests. The server decides what actually gets written.

Prices, coupons and totals are all re-checked on the trusted side before an order exists — and if a shopper leaves before paying, the cart is already saved and handed to Cart Recovery.

server · placeOrder()
Re-resolves every price from your product variants; the client's price is never trusted
Fails the order outright if a variant is inactive or missing
Re-validates the coupon against the server's own subtotal, not the browser's
Short-circuits a double-submit with an idempotency key
Writes the order, its items, its status history and coupon redemptions, with per-user caps

Everything the browser sends is treated as a suggestion. The order that gets written is the one the server can prove: priced, taxed and validated on the trusted side.

Snapshots every 10 seconds

Leave without paying, and nothing is lost.

The checkout quietly snapshots the cart and contact every ten seconds. If a shopper drops off, the handoff is already made.

Cart Recovery
picks it up from here

Wins back the checkout that walked away, with a multi-touch, evidence-timed nudge.

See how Cart Recovery works

A checkout that fits how India buys — and how you get paid.

Phone-first for them, proven on the server for you. It ships with your store — live in 7 days, on your own Razorpay, with nothing skimmed off the top.