Skip to main content
Back to blog
Subscriptions Stripe Payments SaaS

Recurring Subscriptions in Your App: Tech Guide

Implement recurring subscriptions: architecture, Stripe Billing, RevenueCat, dunning and proven design patterns.

JM
Javier Manzano
CEO & Co-founder • June 18, 2026

Recurring subscriptions are the preferred monetization model for apps and SaaS because they generate predictable revenue and improve customer lifetime value. But implementing a well-built recurring billing system is more complex than it seems. In this guide, we share the architecture patterns we use at Soamee to build robust subscription systems in production.

Why Implementation Matters More Than You Think

The difference between a mediocre and an excellent subscription system can represent 20-30% of your MRR. Good dunning (failed payment management) can recover 40-60% of transactions that initially fail. A well-designed trial can convert 80-95% of users who start it. And correct prorations prevent customer disputes and losses from incorrect charges.

We have seen startups lose thousands of euros per month from naive implementations: payment retries all happening at the same time saturating the queue, prorations that do not account for actual days in the month, trials that expire without notifying users, and cancellations that do not properly release plan permissions.

Architecture of a Subscription System

Main Components

A complete subscription system has these components:

  1. Subscription Engine: manages subscription states (active, trialing, past_due, canceled, paused).
  2. Billing Engine: calculates amounts to charge, prorations, and generates invoices.
  3. Payment Processor: executes charges (Stripe, Redsys, RevenueCat).
  4. Dunning System: manages failed payment retries and user communication.
  5. Entitlement System: controls which features each user has access to based on their plan.
  6. Analytics: MRR metrics, churn, LTV, trial conversion.

State Pattern

The subscription lifecycle follows this state machine:

[trialing] → [active] → [past_due] → [canceled]
     ↓            ↓           ↓
 [canceled]   [paused]   [active] (if payment recovered)

Each state transition must:

  • Update user permissions (entitlements).
  • Send appropriate communication (email, push notification).
  • Register the event for analytics.
  • Execute billing logic (charge, stop charging, prorate).

Option 1: Stripe Billing

Stripe Billing is our default recommendation for web subscriptions. It handles the complexity of recurring billing and lets you focus on your product.

Basic Integration

The minimum integration with Stripe Billing involves:

  1. Create products and plans in Stripe (via API or dashboard).
  2. Checkout Session for users to subscribe with a hosted or embedded payment flow.
  3. Webhooks to synchronize subscription state with your database.
  4. Customer Portal for users to manage their subscription (change plan, cancel, update payment).

Critical webhooks you must handle:

  • customer.subscription.created: new subscription created.
  • customer.subscription.updated: plan change, state, or period change.
  • customer.subscription.deleted: subscription definitively canceled.
  • invoice.paid: successful payment, activate/renew access.
  • invoice.payment_failed: payment failed, initiate dunning.
  • customer.subscription.trial_will_end: trial about to end (3 days before).

Trial Management

Stripe supports trials natively. Configurations we recommend:

  • Trial without card: higher trial volume but lower conversion. Useful for products with network effects needing critical mass.
  • Trial with card: lower volume but higher conversion (user already has payment intent). Our default recommendation.
  • Duration: 7-14 days is standard. GolfyApp uses 7 days with 95% conversion results.

The key to trial conversion is activation. If the user experiences the core product value during the trial, they will convert. Our strategy:

  1. Day 0: welcome email with quick start guide.
  2. Day 1-2: if they have not used the main feature, email with specific tutorial.
  3. Day 5 (7-day trial): reminder that trial ends in 2 days + summary of value received.
  4. Day 6: final reminder with special offer if they convert today.

Prorations

Stripe automatically calculates prorations when a user changes plans mid-cycle. There are three strategies:

  • create_prorations (default): charge/credit the proportional difference. If a user moves from Basic Plan (10 EUR/month) to Pro Plan (30 EUR/month) mid-month, they are charged an additional 10 EUR for the remaining 15 days.
  • none: do not prorate. The new plan takes effect on the next cycle.
  • always_invoice: generate immediate invoice for the difference.

Dunning

Stripe has Smart Retries that uses ML to decide when to retry a failed payment. We complement with:

  • Automatic email to the user when a payment fails with a link to update payment method.
  • 3 retries over the following 7 days at variable times.
  • If after 3 attempts it still fails, mark as past_due and notify that service will be suspended in 3 days.
  • After 10 days without payment, cancel the subscription.

This configuration allows us to recover 50-60% of failed payments.

Option 2: RevenueCat for Mobile Apps

If your app lives on iOS and/or Android, in-app subscriptions have their own rules. Apple and Google manage the charges, but you need a backend to unify state.

Why RevenueCat

  • One SDK, two stores: abstracts differences between App Store Connect and Google Play Billing.
  • Server-side validation: validates receipts automatically without your backend touching Apple/Google APIs.
  • Unified webhooks: a single endpoint receives events from both stores.
  • Analytics: unified subscription metrics (MRR, churn, trial conversion) between iOS and Android.
  • Experiments: A/B testing of pricing and paywalls without publishing a new version.

Integration with RevenueCat

  1. SDK in the app: configure RevenueCat SDK (Swift, Kotlin, React Native, Flutter).
  2. Products in stores: create subscription products in App Store Connect and Google Play Console.
  3. Mapping in RevenueCat: configure “Entitlements” that map products to permissions.
  4. Webhooks to your backend: synchronize subscription state with your database.
  5. Paywalls: design purchase screens with RevenueCat components or custom.

Store Particularities

There are important differences between Apple and Google:

  • Commissions: both charge 30% in the first year, 15% after (Small Business Program: 15% from the start if you invoice less than 1M USD/year).
  • Grace periods: Apple gives 6-16 days of grace for failed payments. Google gives 3-30 configurable days.
  • Cancellation: on iOS, access continues until end of paid period. On Android, you can revoke immediately or at end.
  • Pricing: Apple requires prices from their predefined catalog. Google allows free pricing.
  • Family sharing: Apple supports sharing subscriptions with family. Google too but with differences.

The PEMAV Case

In PEMAV we implemented RevenueCat to manage subscriptions on iOS and Android with a single backend. Key learnings:

  • Synchronization between store state and your backend can have delays of up to minutes. Design for eventual consistency.
  • Users who switch devices (from Android to iOS or vice versa) need a robust “restore purchases” mechanism.
  • Introductory offers (first month free, 3 months at 50%) are very effective in stores and RevenueCat handles them well.

Option 3: Custom Billing on Redsys

If you need to use Redsys for subscriptions due to commission or regulatory requirements, you must build the billing logic yourself. Redsys only provides tokenization and charging; the rest is your responsibility.

Architecture with Redsys

  1. First transaction: CIT (Cardholder Initiated) with 3D Secure that returns a COF token.
  2. Recurring charges: MIT (Merchant Initiated) with the stored token, without user intervention.
  3. Your billing engine: a service that executes charges according to your plan logic:
    • Cron job or scheduler that identifies subscriptions to renew each day.
    • Retry logic with exponential backoff for failed payments.
    • Proration calculation when users change plans.
    • Invoice generation with correct tax data.

When It Makes Sense

We only recommend custom billing on Redsys when:

  • You process very high volumes in Spain and the commission difference justifies the development.
  • You have regulatory requirements mandating local bank processing.
  • Your billing model is so specific that neither Stripe Billing nor any platform supports it natively.

In all other cases, Stripe Billing saves months of development and maintenance.

Design Patterns for Subscriptions

Feature Flags per Plan

The pattern we use to control feature access:

Plan → [Feature Flags] → Entitlements

Example:
- Free Plan: max_projects=3, api_calls=1000/month, no_export
- Pro Plan: max_projects=unlimited, api_calls=50000/month, export_csv
- Enterprise: everything + sso + audit_logs + api_unlimited

Feature flags are loaded at session start and cached. When the plan changes (via webhook), the cache is invalidated and entitlements are reloaded.

Metering for Usage-Based Billing

If your pricing has a usage component, you need a metering system:

  1. Record usage: each metered action (API call, message, GB) is registered in a counter.
  2. Aggregate by period: at the end of the billing period, the total is calculated.
  3. Report to Stripe: Stripe Usage Records API allows reporting usage which it invoices automatically.

The trick is that metering must be eventually consistent but not lose events. We use Redis for real-time counters and PostgreSQL as source of truth with periodic reconciliation.

Cancellation with Retention

The cancellation flow is a retention opportunity:

  1. Reason survey: why are they canceling (price, not using, alternative, etc.).
  2. Contextual offer: based on the reason:
    • If price → offer discount or lower plan.
    • If lack of use → offer temporary pause (1-3 months).
    • If alternative → show unique features they might not know about.
  3. Confirmation: if they insist on canceling, confirm and ask if they want access until end of period.

In GolfyApp, this retention flow reduces voluntary cancellation by 30%.

Metrics You Must Track

A subscription system without analytics is like driving without a speedometer. Minimum metrics:

  • MRR (Monthly Recurring Revenue): recurring revenue normalized to monthly.
  • Churn rate: percentage of subscribers who cancel per month (voluntary + involuntary).
  • Trial conversion rate: percentage of trials that convert to paid.
  • Expansion MRR: additional revenue from upgrades and add-ons.
  • Net Revenue Retention: measures whether existing customers spend more or less over time (target: >100%).
  • LTV: total value a customer generates during their lifetime (MRR / churn rate).
  • Dunning recovery rate: percentage of failed payments that are recovered.

Step-by-Step Implementation

Week 1-2: Foundations

  1. Define plans and pricing.
  2. Create products in Stripe / configure RevenueCat.
  3. Implement checkout / paywall.
  4. Configure basic webhooks (created, updated, deleted).
  5. Implement entitlement system (feature flags per plan).

Week 3: Trial and Conversion

  1. Configure trial (duration, with/without card).
  2. Implement automated emails during trial.
  3. Configure Customer Portal / subscription management screen.
  4. Implement upgrade/downgrade flow with prorations.

Week 4: Dunning and Retention

  1. Configure Smart Retries in Stripe.
  2. Implement failed payment emails with update link.
  3. Implement cancellation flow with retention.
  4. Configure subscription analytics.

Week 5+: Optimization

  1. A/B testing of pricing and paywalls.
  2. Trial communication optimization.
  3. Cohort analysis and churn by segment.
  4. Metering implementation if applicable.

Common Mistakes to Avoid

  1. Not handling the invoice.payment_failed webhook: without dunning, you lose 20-40% of renewals from failed payments.
  2. Incorrect prorations: not correctly calculating days in the current period generates disputes.
  3. Race conditions in webhooks: Stripe can send webhooks out of order. Your system must be idempotent.
  4. Not caching entitlements: checking the plan on every request is a bottleneck. Cache and invalidate via webhook.
  5. Trial without activation: a trial where the user does not experience core value has 0% conversion.
  6. Immediate cancellation without access: if you cancel and cut access immediately, the user feels they lost money (paid for the period but cannot use it).

Conclusion

Implementing recurring subscriptions correctly requires thinking about the complete lifecycle: from acquisition (trial) to retention (dunning, cancellation with offers) through expansion (upgrades, add-ons). The technology exists (Stripe Billing, RevenueCat) to avoid reinventing the wheel, but the business logic you build on top is what makes the difference between a business that grows and one that loses customers through attrition.

If you need to implement a subscription system in your app or platform, contact our team. We have built billing systems in production with 95% conversion rates and 60% recovery rates.

Don't miss a thing

JM

Javier Manzano

CEO & Co-founder at Soamee

Passionate about technology and software development. Sharing knowledge and experiences to help other developers grow.

Did you enjoy this article?

If you need help with your development project, we are here for you.

Book a free call →