Skip to content
SaaS onlyMulti-tenant design
Call now +1 (929) 450-3261
Billing

SaaS billing with Stripe: the edge cases to plan for

6 min read

SaaS billing with Stripe: the edge cases to plan for

The first Stripe payment is easy. Webhooks, failed cards, proration, refunds and tax are where subscription billing breaks. Here is what to plan for before launch.

Short answer: Stripe makes the first payment easy, and the hard part is everything after it. Failed cards, upgrades in the middle of a billing period, refunds, taxes, trials and webhooks that arrive late or twice are where subscription products break. Plan for these cases before launch, store a clear copy of billing state in your own database, and test each case in Stripe's test mode.

This article lists the edge cases we plan for when building subscription billing. It is general engineering guidance and not tax or legal advice. For related work, see our page on fintech and billing SaaS.

Treat webhooks as the source of truth

The redirect back to your site after checkout is not proof of payment. A user can close the tab, lose connection or return before the payment settles. Your system should change a customer's access based on events Stripe sends to a webhook endpoint, not on the browser landing page.

A reliable webhook handler does a few specific things:

  • Verifies the signature on every request, so that outsiders cannot fake events.
  • Is idempotent. Stripe can deliver the same event more than once. Record each event id you have processed and ignore repeats.
  • Tolerates disorder. Events can arrive out of sequence. Where it matters, fetch the current object from Stripe instead of trusting the order of arrival.
  • Responds quickly. Acknowledge first, then do slow work in a background job, so Stripe does not time out and retry.
  • Can be replayed. Keep the raw events, so that after a bug fix you can reprocess them.

Handlers that skip these steps tend to work in demos and fail quietly in production, with customers paying and not getting access, or the reverse.

Tangled cables on a pale desk beside a small dark card reader

Failed payments and dunning

Cards expire, hit limits and get replaced. A share of renewals will fail in any subscription product, so decide what happens next. Stripe can retry failed invoices on a schedule you configure and can send its own emails, but you still choose the product behavior: does the customer keep access during a grace period, see a banner, lose features, or get suspended? Write that policy down before you code it.

Make it easy to recover. A link to update the payment method, a clear message inside the app and a final notice before cancellation reduce avoidable churn. Also confirm that your own system reacts to the event that marks a subscription as past due and to the one that marks it canceled, and that each has a test. Check the shape of the event data against the API version you use, since fields differ between versions.

Upgrades, downgrades and proration

When a customer changes plan in the middle of a billing period, you must decide how the difference is charged. Stripe can prorate by default, charging or crediting for the unused time, or you can change the plan at the next renewal instead. Both are valid. What causes trouble is not choosing: finance, support and the product page then give different answers.

Things to settle in writing:

  • Do upgrades take effect immediately, and is the extra charge billed now or on the next invoice?
  • Do downgrades wait until the end of the period?
  • What happens to usage limits and seats when a plan changes?
  • How are add-ons and per-seat charges handled when seats are added and removed?

Trials, coupons and free plans

Trials add states: trialing, converted, expired without a card and canceled during the trial. Decide whether a card is required up front, because it changes both sign-up rates and the number of failed conversions. Coupons and promotion codes need rules for duration, stacking and eligibility. Each of these is one more combination to test, so keep the offer set small at launch.

Refunds, disputes and credits

A refund in Stripe does not by itself cancel the subscription or remove access in your app. Decide who can issue refunds, whether access ends at the same time, and how a partial refund appears in the customer's account. Disputes, also called chargebacks, bring their own deadlines and evidence requests, so make sure someone receives the notification and knows where to respond. Credits and account balances help for goodwill adjustments, but they should appear in your own records so support can explain them.

Taxes, invoices and currencies

Sales tax, VAT and similar taxes depend on where you and your customers are, and the rules change. Stripe offers tools to calculate and collect tax, and you still need to confirm your registration and filing obligations with an accountant or tax adviser. Collect the billing country and, for business customers, a tax number if your markets need it. If you sell in more than one currency, decide whether prices are set per currency or converted, and how refunds behave when exchange rates have moved.

Invoices should carry the details your customers' finance teams expect. Keep invoice numbering, company names and addresses editable through the customer portal where that is allowed, and test the full path from checkout to a downloadable invoice.

Keep your own record and test the odd paths

Store the customer id, subscription id, plan, status and period dates in your own database, updated from webhooks. This keeps your app fast, lets support see state without opening the dashboard and gives you a base for usage limits and reporting. Reconcile it against Stripe on a schedule, so drift is caught early.

Use test mode and test clocks to simulate renewals, failures and trial endings without waiting. A short checklist to run before launch:

  1. Successful sign-up, renewal and cancellation.
  2. A card that fails at renewal, then a card update that succeeds.
  3. An upgrade and a downgrade mid-period.
  4. A refund and a dispute notification.
  5. The same webhook delivered twice and two events arriving out of order.

Limits to keep in mind

Billing logic touches money and customer trust, so mistakes are visible. No design removes all risk, and payment provider rules, fees and APIs change over time. We build and test the integration, and your business remains responsible for its pricing, tax compliance and payment provider agreement.

If you would like to plan your billing flow, chat on WhatsApp at +1 (929) 450-3261 or message us on Telegram and tell us your plans, whether you charge per seat or by usage, and the countries you sell in.

Chat on WhatsApp