Subscription billing looks like a solved problem until you ship it. You wire up a checkout, see the first successful charge, and feel done—right up until a customer upgrades mid-cycle and gets charged twice, a card expires and the renewal silently fails, or your revenue numbers and your payment provider's dashboard disagree by a few thousand rupees with no obvious reason why. In April 2025, as more Indian product teams moved from one-time payments to recurring revenue—nudged along by Razorpay's maturing subscriptions APIs and the RBI's settled e-mandate framework for recurring card payments—a lot of teams discovered the same thing we did: the charge is the easy 10%. The other 90% is trials, proration, dunning, webhooks, and tax. As the CTO at Softechinfra, I have debugged enough of these edge cases across our web development projects to know they are predictable. This guide is the durable version: the concepts that do not change even as the APIs do.
The Mental Model: Your Database Is the Source of Truth
The first and most expensive mistake teams make is treating the payment provider as their billing database. Stripe and Razorpay are excellent at moving money and storing payment instruments. They are not where your application should read a user's entitlements at request time.
The durable pattern is simple: the provider owns the money, your database owns the truth. Every meaningful event—subscription created, renewed, upgraded, cancelled, payment failed—arrives as a webhook, and your system records its own local representation of the subscription state. When a user loads the app, you check your database, not a synchronous API call to Stripe. This keeps your app fast, keeps it working when the provider has a blip, and gives you a billing history you actually own.
This separation also makes provider choice less terrifying. Whether you run Stripe for international cards, Razorpay for the India-specific stack (UPI AutoPay, e-mandates, netbanking), or both in parallel, the internal subscription model your app reads from stays the same. The provider becomes an integration detail behind a thin abstraction rather than a decision baked into every feature.
Trials and the Activation Problem
Free trials are a product decision dressed up as a billing feature, and the implementation choice you make has real consequences. There are two honest models, and you should pick deliberately.
| Trial Model | How It Works | Best For |
|---|---|---|
| Card-required trial | Capture the payment method up front; auto-convert to paid at trial end | Higher-intent products; reduces tyre-kickers; smoother conversion |
| Card-free trial | Grant access with no payment method; prompt for a card before conversion | Top-of-funnel growth; lower friction; needs strong in-trial activation |
The card-required model converts more cleanly but shrinks the top of your funnel and—critically in India—runs into the e-mandate flow, where the first charge must clear an explicit authorization step. The card-free model maximizes signups but pushes the entire conversion burden onto the trial-end moment, which is exactly when a failed or abandoned card-entry quietly costs you the customer.
Whichever you choose, the durable rule is the same: the trial-to-paid transition is the single highest-leverage event in your billing system. Instrument it heavily. Know your trial-end success rate, your card-decline rate at conversion, and how many users you lose between "trial ended" and "card captured." We learned to obsess over this on TalkDrill, our in-house English-speaking app (talkdrill.com), where the gap between the end of a free practice window and the first successful recurring charge was where most preventable churn was hiding.
Proration: The Math That Quietly Goes Wrong
Proration is the calculation that runs when a customer changes plans mid-cycle. Upgrade from a 999/month plan to a 1,999/month plan on day 15, and they should be charged for the unused portion of the new plan minus the unused portion of the old one—not a full extra month, and not nothing.
Both Stripe and Razorpay can compute this for you, and you should let them. The bugs do not come from the arithmetic; they come from the policy decisions you forgot to make explicit:
- On an upgrade, do you charge the prorated difference immediately, or add it to the next invoice?
- On a downgrade, do you refund the difference, issue account credit, or apply the new price only at the next renewal?
- What happens to an annual plan changed mid-term—does the unused balance convert to credit?
- If a customer upgrades, downgrades, and upgrades again in one cycle, does your invoice still read sensibly to a human?
The right answer is almost always: upgrades take effect and bill immediately; downgrades take effect at the next renewal. This is easier to reason about, harder to abuse, and produces invoices customers can actually understand. Whatever you decide, write the policy down in plain language before you write the code—proration disputes are almost always policy ambiguity surfacing as a support ticket, not a math error.
Dunning: Recovering the Payments That Quietly Fail
Here is the statistic that reframes the whole problem: a meaningful share of subscription churn is not customers deciding to leave. It is cards expiring, hitting limits, or getting declined—and nobody following up. This is called involuntary churn, and dunning is the system that recovers it.
A dunning sequence is the automated retry-and-notify logic that fires when a recurring charge fails. A durable one looks like this:
- Retry on a smart schedule. Not five times in an hour. Space retries over days—e.g. day 1, day 3, day 5, day 7—so a temporary decline or a topped-up card has time to clear.
- Email at each failure with a one-click fix. Every dunning email links straight to a hosted page to update the card. Friction here is lost revenue.
- Degrade access gracefully, not instantly. Give a grace period before you cut off a paying customer. Cutting access on the first failed retry punishes loyal customers for their bank's decision.
- Define a final state. After the retry window closes, the subscription moves to a defined "past due" or "cancelled" state—recorded in your database, not left ambiguous.
Both providers offer built-in dunning (Stripe's Smart Retries, Razorpay's retry logic), and for most teams the built-in flows are the right starting point—turn them on before you build anything custom. The reason dunning earns its own section is that it is the highest-ROI billing work most teams never prioritize: every recovered involuntary failure is revenue you already earned and were about to lose for free.
Webhooks: The Nervous System You Cannot Skip
If the database-as-truth model is the skeleton of your billing system, webhooks are the nervous system. Almost everything that matters happens asynchronously—a renewal succeeds at 3 a.m., a card fails on a retry, a dispute is opened—and the only way your application hears about it is through webhook events. Get webhooks wrong and your billing state silently drifts from reality.
Three rules make webhook handling reliable, and they hold regardless of provider:
Verify every signature
Both Stripe and Razorpay sign their webhooks. Reject any payload whose signature does not verify—an unsigned billing webhook is an attacker telling you a payment succeeded when it did not.
Make handlers idempotent
The same event will arrive more than once. Key processing on the event ID so a duplicate "payment succeeded" never grants two months of access or double-counts revenue.
Acknowledge fast, process async
Return 200 immediately, then do the real work on a queue. Slow handlers cause the provider to retry, which floods you with duplicates—exactly what idempotency then has to absorb.
Idempotency deserves the emphasis. Webhook delivery is "at least once," never "exactly once." The discipline of keying every side effect on a unique event ID is the same defensive habit we apply to payment endpoints and integration boundaries generally; it is closely related to the input-validation and trust-boundary thinking in our API design best practices guide. Assume duplicates and out-of-order delivery, and build so neither can corrupt state.
Taxes, Compliance, and Reconciliation
Tax is where billing stops being an engineering problem and becomes a finance-and-legal one—which is precisely why engineers under-scope it. For Indian businesses, GST is not optional decoration on the invoice: rate, place of supply, and whether the customer is B2B (with a GSTIN, eligible for input credit) or B2C all change what a compliant invoice must contain. For international customers, you are suddenly in the world of VAT, GST in other jurisdictions, and US sales tax nexus.
You do not have to solve all of this on day one, but you do have to decide who owns it. The durable options:
- Use the provider's tax tooling or a dedicated tax engine to calculate at checkout—correct rates, applied automatically.
- Generate compliant tax invoices (with the right fields for your jurisdiction) and store them immutably.
- Run a monthly reconciliation: your database's recorded revenue must match the provider's settlement reports must match what your accounting sees.
That third point is the one teams skip and regret. Reconciliation is not a finance afterthought; it is your billing system's test suite. If your internal revenue numbers and the provider's payout reports diverge, something in your webhook handling, proration, or refund logic is broken—and reconciliation is how you catch it before an auditor or a customer does. The same compliance-first instinct runs through how we approached India's regulatory surface in our fintech compliance primer, and the broader build decision in our custom billing software guide.
A Build Order That Keeps You Sane
Knowing the pieces is not the same as knowing the order to build them. Sequencing badly means rework; here is the order that has held up for us across projects:
- Model subscription state in your own database first. Plans, statuses, billing periods—before you touch a provider SDK.
- Wire one provider's checkout for the simplest plan. Single plan, no trial, no proration. Get one clean charge end to end.
- Build webhook handling with signature verification and idempotency. This is the foundation everything else sits on—do it before you add features.
- Add trials, then upgrades/downgrades with proration. One at a time, each with its policy written down.
- Turn on provider dunning and graceful access degradation.
- Add tax calculation, compliant invoices, and monthly reconciliation.
Notice that revenue analytics are not a separate phase—if you built database-as-truth correctly, your MRR, churn, and renewal metrics fall out of the subscription table you already maintain, which is exactly the instrumentation we argue for in our SaaS metrics dashboard guide. And if you are running billing across multiple plans and customer types, the tenant-isolation thinking in our multi-tenant architecture guide pairs naturally with this work.
Stripe and Razorpay are both excellent—the right choice depends on your market, your customers' payment habits, and your compliance footprint, not on which has the prettier docs. Build the durable structure underneath, and switching or running both becomes a manageable integration detail rather than a rewrite.
Building Subscriptions Into Your Product?
We implement and debug subscription billing—Stripe, Razorpay, trials, proration, dunning, webhooks, and GST-compliant invoicing—as part of our product engineering work. Let's make your recurring revenue boringly reliable.
Talk to Our Engineering Team →
