Skip to content
Back to blog

Industry GuidesSaaS

Managing Downgrades, Upgrades, and Proration in Your SaaS Payments

Master the art of managing subscription changes in your SaaS. This technical tutorial covers proration calculations, credit handling, webhooks, plan migration, and automated customer communication to reduce churn and optimize revenue.

Bridge Pay editorial team

12 min read

Managing Downgrades, Upgrades, and Proration in Your SaaS Payments
Table of contents
  1. Flexibility is Key to SaaS Retention
  2. Prerequisites: The Foundations of Your Subscription System
  3. Detailed Steps for Managing Plan Changes
  4. Code Example: Webhook Handler
  5. Verification: How to Ensure Everything Works?
  6. Troubleshooting: Common Problems and Solutions
  7. Conclusion

Flexibility is Key to SaaS Retention

In the competitive world of B2B SaaS, the ability to adapt to your customers''' evolving needs isn'''t a luxury: it'''s a necessity. Managing subscriptions, and more specifically plan changes (upgrades and downgrades), is at the heart of this flexibility. Clumsy handling can lead to customer frustration, billing errors, and ultimately, churn. Studies show that nearly 15% of involuntary churn in SaaS is due to billing issues, including opaque management of plan changes.

Conversely, a seamless and transparent experience during an upgrade or downgrade builds trust and can directly impact your customers''' Lifetime Value (LTV). It'''s about allowing them to scale up as they grow, or scale back during periods of consolidation, without administrative friction.

This technical tutorial will guide you step-by-step through setting up a robust system to manage subscription changes, proration calculations, and the associated communication. We'''ll see how a modern payment gateway like Bridge Pay, designed for complex models, can make your life much easier.

Prerequisites: The Foundations of Your Subscription System

Before diving into the logic of plan changes, make sure the foundations of your system are solid. Good preparation will save you many headaches. Here are the essential elements:

  • Multiple defined pricing plans: You must have at least two plans (e.g., "Basic" and "Pro") with distinct features and prices, stored in your database with unique identifiers (e.g., plan_basic_monthly, plan_pro_monthly).
  • A functional payment integration: Your application must already be connected to a payment gateway capable of handling recurring payments. This is where a solution like Bridge Pay comes in, offering clear APIs for subscription management.
  • A data model for subscriptions: In your database, a subscriptions table is essential. It must contain at a minimum: id, user_id, plan_id (a foreign key to your plans), status (e.g., active, canceled, past_due), current_period_start, and current_period_end.
  • Access to your development environment: You will need backend access to implement the logic, and API keys from your payment gateway for the test environment.

Detailed Steps for Managing Plan Changes

Step 1: Map the User Journey and Triggers

The first step is to define where and how a user can change their plan. This usually happens in a "Billing" or "Subscription" section of their account. The interface should clearly present the available plans, highlight the current plan, and offer action buttons like "Upgrade to Pro" or "Switch back to Basic."

When a user clicks one of these buttons, two scenarios arise:

  • Upgrade: Moving to a higher (more expensive) plan. Access to new features is usually immediate. Billing must be adjusted on a prorated basis for the current period.
  • Downgrade: Moving to a lower (less expensive) plan. The change takes effect at the end of the current billing period to avoid having to refund the user. they will continue to benefit from the features of their higher plan until the renewal date.

The technical trigger is a call from your frontend to your backend (e.g., POST /api/subscription/change). This call must contain the user'''s ID and the desired new plan ID. Your backend then takes over to orchestrate the next steps.

Step 2: Proration Logic - The Core Engine

Prorated calculation is essential for fair billing. It involves charging only for the actual time used on each plan. Here'''s how to approach it:

For an Upgrade:

  1. Calculate the unused cost of the old plan: (Old Plan Price / Days in period) * Remaining days.
  2. Calculate the cost to be used for the new plan: (New Plan Price / Days in period) * Remaining days.
  3. The difference is the amount to be billed immediately: New plan cost - Old plan cost.

Concrete example: A user upgrades from the "Pro" plan (€99/month) to the "Enterprise" plan (€249/month) on the 15th of a 30-day month. They have 15 days left in their subscription period.

  • Credit for unused time on "Pro": (€99 / 30) * 15 = €49.50
  • Cost for time to be used on "Enterprise": (€249 / 30) * 15 = €124.50
  • Amount for the upgrade to be billed immediately: €124.50 - €49.50 = €75

Payment gateways like Bridge Pay make this incredibly simple. Instead of doing these calculations yourself, you can simply call their subscription update API, specifying the desired proration behavior. Bridge Pay automatically calculates the amount, generates an invoice, and attempts the payment.

Step 3: Handling Downgrades and Credits

Managing downgrades is different because nothing is billed immediately. The best practice is to credit the user for future use.

The logic is as follows:

  1. The change is recorded but only takes effect at the end of the current billing period. In your database, you can use a field like scheduled_plan_change to store the plan to which the user will migrate.
  2. The user retains access to their higher plan until the renewal date.
  3. On the renewal date, the subscription switches to the new (less expensive) plan and renews at that rate.

Some business models choose to apply a prorated credit for the unused time on the higher plan, which will be deducted from the next invoice. This can be a welcome commercial gesture. Bridge Pay handles this case by automatically applying a credit to the customer'''s account, which will be used for their next invoices.

Example: A user downgrades from the "Pro" plan (€99) to "Starter" (€49) mid-period. They paid €99 for the month. Instead of billing them €49 the following month, you can credit them the €49.50 of unused time, and their next invoice will be €0, with the balance carried forward.

Step 4: Update the Subscription via the Payment API

Once the logic is defined, it must be translated into an API call. This is the action that modifies the subscription directly with your payment provider. With a gateway like Bridge Pay, this looks like a call to a PATCH /v1/subscriptions/{subscription_id} endpoint.

The request body for an immediate upgrade would contain:

{
    "plan_id": "plan_enterprise_monthly",
    "proration_behavior": "create_prorations"
}

The proration_behavior: create_prorations option tells Bridge Pay to calculate the proration and immediately bill the difference. If the payment fails (e.g., expired card), the API will return an error, and the subscription will not be changed. You can then prompt the user to update their payment information.

For a downgrade at the end of the period, the request would be:

{
    "plan_id": "plan_starter_monthly",
    "proration_behavior": "none",
    "cancel_at_period_end": false // Important: we don'''t want to cancel, just change the plan
}

Internally, in your system, you schedule the effective update. However, the best gateways allow you to schedule this change directly via the API.

Step 5: Use Webhooks to Synchronize Your Database

Never rely solely on the response from the initial API call. Payment operations are asynchronous. The source of truth must be the events sent by your payment gateway via webhooks.

Set up an endpoint on your server (e.g., POST /webhooks/bridgepay) to listen for events. The key event is subscription.updated. When a plan change is effective, Bridge Pay will send an event to this URL with all the updated subscription information.

Your webhook logic should:

  1. Verify the webhook signature: This is a crucial security step to ensure the request is coming from Bridge Pay and not a malicious actor.
  2. Parse the event payload: The JSON object will contain the new plan_id, the status, and the new current_period_start and current_period_end dates.
  3. Update your local database: Modify the user'''s subscription record to reflect this new information. It is this update that will unlock/restrict features in your application.

Step 6: Automate Customer Communication

A user should never be surprised by an invoice. Clear, automated communication is the final piece of the puzzle for a successful experience. Trigger transactional emails at each key stage:

  • Upgrade Confirmation: Send an email immediately after the prorated payment succeeds. "Congratulations, your upgrade to the Enterprise plan is now active. Here is your invoice for €75 for the current period. You can now access [Feature X]."
  • Downgrade Request Confirmation: "We have received your request to switch to the Starter plan. This change will take effect at the end of your current billing period on [end of period date]. Until then, you will retain access to all Pro plan features."
  • Notification of Effective Change (Downgrade): On the renewal date, send a reminder: "Your subscription has been switched to the Starter plan as requested. Your next invoice on [date] will be for €49."

These emails significantly reduce your customer support workload and reinforce the perception of a professional and transparent service.

Code Example: Webhook Handler

Here is a simplified example in Python (with a Flask-like framework) of what a webhook handler for the subscription.updated event might look like.


import json
import stripe # Assuming an API similar to Stripe, like Bridge Pay'''s
from flask import Flask, request, abort

app = Flask(__name__)

# Retrieve this secret from your Bridge Pay dashboard
WEBHOOK_SECRET = 'whsec_your_secret_key'

@app.route('/webhooks/bridgepay', methods=['POST'])
def bridgepay_webhook():
    payload = request.data
    sig_header = request.headers.get('BridgePay-Signature')

    try:
        event = stripe.Webhook.construct_event(
            payload, sig_header, WEBHOOK_SECRET
        )
    except ValueError as e:
        # Invalid payload
        return 'Invalid payload', 400
    except stripe.error.SignatureVerificationError as e:
        # Invalid signature
        return 'Invalid signature', 400

    # Handle the event
    if event['type'] == 'subscription.updated':
        subscription_data = event['data']['object']
        handle_subscription_updated(subscription_data)
    # ... handle other event types

    return 'Success', 200

def handle_subscription_updated(subscription):
    user_id = get_user_id_from_subscription(subscription) # Logic to be implemented
    new_plan_id = subscription['plan']['id']
    new_status = subscription['status']
    new_period_end = subscription['current_period_end']

    # Update the database
    db.update_subscription(
        user_id=user_id, 
        plan_id=new_plan_id, 
        status=new_status, 
        period_end=new_period_end
    )
    
    # Logic to provision/de-provision access to features
    update_user_permissions(user_id, new_plan_id)

    print(f"Subscription {subscription['id']} for user {user_id} was updated to plan {new_plan_id}.")

Verification: How to Ensure Everything Works?

Once your implementation is complete, it is crucial to test it under real conditions (in your test environment). Here is a verification checklist:

  • Upgrade Test: Simulate an upgrade. Check in the Bridge Pay dashboard that a prorated invoice has been generated and paid. Ensure the user has immediate access to the new features.
  • Downgrade Test: Simulate a downgrade. The change should not be immediate. Verify that your database has recorded a scheduled change. On the simulated renewal date, make sure the plan changes, feature access is restricted, and the new invoice has the correct amount.
  • Email Verification: Confirm that all transactional emails (confirmation, notification) are sent at the right time and with the correct information.
  • Webhook Logs: Monitor the logs in your Bridge Pay dashboard to ensure events are being sent correctly and your server is returning a success code (200).

Troubleshooting: Common Problems and Solutions

Even with good preparation, problems can arise. Here are the most common ones:

  • Problem: Webhooks are not being received by my server.
    Solution: Check the webhook URL in your Bridge Pay dashboard. Ensure it is publicly accessible. Inspect your firewall or server error logs. Bridge Pay usually provides a log of webhook attempts that will show you the HTTP error code received (e.g., 500, 404).
  • Problem: The proration calculation seems incorrect.
    Solution: If you are doing the calculation manually, be careful with time zones and rounding of days/seconds. This is a frequent source of errors. That'''s why it is highly recommended to rely on your payment gateway'''s built-in proration feature. If the amount calculated by Bridge Pay seems incorrect, verify that your plan prices are correctly configured in the dashboard.
  • Problem: The user changed their plan, but their feature access hasn'''t been updated.
    Solution: This is almost always a problem with your webhook handler logic. Make sure you are correctly identifying the user and that your update_user_permissions function is being called after the database update. Add logs to trace the data flow from webhook reception to permission updates.

Conclusion

Managing upgrades and downgrades is a fundamental component of the SaaS customer experience. By handling it with technical rigor and transparency, you turn a potential point of friction into a driver of retention and trust. Using a modern and flexible payment gateway like Bridge Pay is a major asset, as it abstracts away much of the complexity of calculations and payment flows.

By following the steps in this guide (modeling, calculation, communication, and verification) you will build a resilient system that supports your customers''' growth and your own.

Ready to simplify your subscription management and focus on your product? Create your Bridge Pay account today and discover an API designed for SaaS flexibility.

SaaS: accept payments with Bridge Pay

An analyst who knows your sector reviews your application. First response within 24-48h, no setup fees.

  • PCI DSS
  • No setup fees
  • First response within 24-48h