Upgrading and Downgrading Subscriptions
Frame supports changing the product tier associated with an active subscription without cancellation. This allows merchants to upgrade or downgrade a customer's subscription while maintaining subscription ID continuity and handling proration automatically.
Overview
When an account moves between pricing tiers, Frame:
- Updates the subscription's associated product and plan
- Calculates a prorated amount based on where the customer is in their billing cycle
- Records the change in a subscription change log
- Handles the billing adjustment at the next renewal or immediately, depending on your chosen proration behavior
Making a Product Change
To change the product on an existing subscription, send a PATCH request to the subscriptions endpoint with the new product ID and your desired proration behavior:
curl --request PATCH \
--url https://api.framepayments.com/v1/subscriptions/:id \
--header 'Authorization: Bearer API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"product": "new_product_id",
"default_payment_method": "new_payment_method_id"
}'
Parameters
| Parameter | Required | Description |
|---|---|---|
product | Yes | The ID of the new product to associate with the subscription |
default_payment_method | No | The ID of the new default payment method to use for the subscription |
Proration Behavior Options
| Value | Description |
|---|---|
always_invoice | Immediately generate an invoice for the prorated difference |
create_prorations | Apply the proration adjustment at the next renewal cycle (default) |
none | No proration; new price takes effect at the next billing cycle |
Upgrades vs Downgrades
Frame determines whether a change is an upgrade or downgrade by comparing the price of the new product against the current product.
- Upgrade: New product price is higher than the current product price. The customer owes the prorated difference for the remaining days in the current billing period.
- Downgrade: New product price is lower than or equal to the current product price. The customer receives a prorated credit applied to their next invoice.
Proration Calculation
Proration is calculated based on the number of days remaining in the current billing period.
Upgrade example:
A customer is on a $100/month plan and upgrades to a $200/month plan on day 15 of a 30-day cycle.
| Step | Calculation | Result |
|---|---|---|
| Days remaining | 30 - 15 | 15 days |
| Daily rate difference | ($200 - $100) / 30 | $3.33/day |
| Proration charge | 15 × $3.33 | $50.00 |
| Next renewal bill | $200 + $50 | $250.00 |
Downgrade example:
A customer is on a $200/month plan and downgrades to a $100/month plan on day 15 of a 30-day cycle.
| Step | Calculation | Result |
|---|---|---|
| Days remaining | 30 - 15 | 15 days |
| Unused credit | (15 / 30) × $200 | $100.00 |
| Next renewal bill | $100 - $100 | $0.00 |
Product Requirements
The new product must meet the following requirements. The API will return an error if any of these conditions are not met:
- Must be a recurring product
- Must be active
- Must have the same currency as the current product
- Must have the same billing interval as the current product (unless
update_interval: trueis passed)
How Proration is Collected
How and when the proration adjustment is collected depends on the proration_behavior you specify.
always_invoice
An invoice is generated immediately for the prorated amount. The invoice is automatically charged to the customer's payment method on file. Once collected, the change log is marked as processed and no further adjustment is made at renewal.
This is equivalent to Stripe's always_invoice behavior and is recommended when you want the customer to settle the difference right away.
create_prorations
No immediate charge is made. The proration adjustment is stored against the subscription and applied at the next renewal:
- For upgrades, the prorated charge is added to the next renewal amount
- For downgrades, the prorated credit is subtracted from the next renewal amount
Once the renewal runs successfully, the adjustment is marked as processed and subsequent renewals return to the standard subscription amount.
none
No proration is calculated or collected. The new product price takes effect from the next billing cycle with no adjustment for the current period.
Subscription Change Log
Every product change creates a SubscriptionChangeLog record that captures the full before and after state of the subscription:
| Field | Description |
|---|---|
previous_product | The product before the change |
new_product | The product after the change |
previous_subscription_plan | The billing plan before the change |
new_subscription_plan | The billing plan after the change |
direction | upgrade or downgrade |
proration_behavior | The proration behavior used |
prorate_amount_cents | The calculated proration amount in cents |
days_remaining | Days left in the billing period at the time of change |
days_in_period | Total days in the current billing period |
effective_date | When the change took effect |
processed | Whether the proration adjustment has been collected |
processed_at | When the adjustment was collected |
invoice_id | The invoice generated for always_invoice behavior |
You can retrieve the change log history for a subscription:
curl --request GET \
--url https://api.framepayments.com/v1/subscriptions/:id/subscription_change_logs \
--header 'Authorization: Bearer API_KEY'
Webhooks
Subscribe to the following webhook event to be notified when a subscription product changes:
customer.subscription.updated: Fired after a successful product change. The event payload includes the updated subscription object.
For details on setting up webhook endpoints and validating signatures, see our Webhooks documentation.
Handling Outcomes
Successful change
On success, the API returns the updated subscription object. The subscription_plan will reflect the new product and pricing.
Validation errors
Subscription not editable
A product change can only be made on an active subscription. Attempting to change the product on a canceled or otherwise non-editable subscription will return:
{
"message": "Subscription in status canceled cannot be modified."
}