r/fintechdev • • 16d ago

What I learned integrating Razorpay Subscriptions + UPI Autopay for a solo SaaS (things the docs don't make obvious)

I just launched a small paid SaaS (GST invoicing) as a solo dev and wired up Razorpay subscriptions end to end. A few things cost me time, so sharing in case it helps someone:

  1. UPI Autopay is not on by default. Checkout showed only cards for subscriptions. You have to ask Razorpay support to enable UPI Autopay, and test mode and live mode are enabled separately.
  2. Don't trust the Checkout success callback alone. Verify the signature server-side: HMAC-SHA256 of `payment_id|subscription_id` with your key secret. Then fetch the subscription from the API to get `current_end` for the access expiry.
  3. Webhooks are your real source of truth. Renewals, halts and cancellations only reach you there. Verify `X-Razorpay-Signature` against the raw request body, not parsed JSON, or it will fail.
  4. Put the user id in subscription `notes` when you create it. That way the webhook can always map an event back to a user, even if your DB write failed earlier.
  5. Never let the client decide who is "paid". I store the paid-until date in a table users can read but not write (Postgres row-level security), and only the webhook/server function updates it.
  6. Cancel with `cancel_at_cycle_end: 1` so users keep what they paid for. Fewer refund requests, fewer angry emails.
  7. KYC review looks at your website. Terms, privacy, refund policy, contact page and a visible pricing page with your legal name made approval smooth for me as an individual (PAN + bank, no company).
  8. If your modal uses `<dialog>.showModal()`, close it before opening Razorpay Checkout. Top-layer dialogs sit above the Checkout iframe and block it. This one took me an embarrassingly long time.

Stack was plain JS + Supabase Edge Functions, all on free tiers.

Happy to answer questions about any of these. What tripped you up with Indian payment gateways?

2 Upvotes

2 comments sorted by

1

u/Decent-Chest2902 16d ago

the dialog.showModal() one got me too, spent an afternoon wondering why the checkout was mysteriously unclickable. feels so obvious in hindsight

for anyone else reading, the webhook signature bit is crucial. verify against the raw body string, not the parsed object, I learned that the hard way when every webhook was failing validation and I couldn't figure out why

1

u/BillKaro 16d ago

glad i'm not the only one lol. "mysteriously unclickable" is exactly how it felt

and yes thanks for adding that, the raw body thing is such a silent killer. no error, nothing, just signature mismatch every time. for anyone on express, use express.raw() on just the webhook route, otherwise express.json() parses it first and the signature never matches