First, some notes
- The
Prorate
flag on the Subscription Update API determines whether the customer is charged pro-rata for additional costs during the current billing period.
- However, once a subscription is running for a customer, the billing date and period is fixed,so by default, Stripe won't actually bill the customer for the
upgraded subscription until the next billing date.
- Note that Stripe uses the
ProrationDate
to the second, so if you show the customer a 'preview' of the changes, that the actual charge might be slightly different by the time it is actioned. Also note that ProrationDate
can't be before the start of the subscription, so be careful if you are e.g. tempted to strip the time off the ProrationDate
(e.g. if the customer changes the subscription on the same day as purchased). Best is to remember the timestamp used in the preview.
- Stripe already has the calculations for changing subscription mid-period, i.e. crediting the customer for unused time on the old subscription, and debiting customer for pro-rated time on the new subscription.
Step 1
Use the UpcomingInvoice
API with the NEW subscription info to see what the price differential will be between old and new subscriptions, like so:
var proRataDate = DateTime.UtcNow; // Or use your clock abstraction
var proRata = new UpcomingInvoiceOptions
{
CustomerId = ...,
SubscriptionId = ...,
SubscriptionItems = ... upgraded InvoiceSubscriptionItemOptions,
SubscriptionProrationDate = proRataDate,
CouponId = ...
};
var upcomingInvoice = await _stripeInvoiceService.UpcomingAsync(proRata);
// Note that UpcomingAsync might return the next full month's bill as well.
var proRataCents = upcomingInvoice.Lines
.Where(l => l.Period.Start?.Date == proRataDate.Date)
.Sum(l => l.Amount);
proRataCents
is the amount that you'll want to show to the customer on the UI as 'due now'.
Step 2
Make the changes to your subscription:
var stripeSubscription = await _stripeSubscriptionService.UpdateAsync(
... subscription id,
new SubscriptionUpdateOptions
{
Prorate = true,
ProrationDate = proRataDate,
CouponId = ...,
Items = ... New subscription items
});
Step 3
If you don't want to wait until the customer's next billing period, you can charge the customer for the difference now (assuming that it's positive). There's likely other ways to do this, but this seems to work, i.e. creating, and then paying an invoice using the existing payment method, for the differential on the subscription. Stripe keeps track of the accounting on the subscription, so the pro-rata amount charged won't be billed again at the start of the next billing cycle.
var invoiceOptions = new InvoiceCreateOptions
{
CustomerId = ... customer id,
AutoAdvance = false,
SubscriptionId = ... subscriptionId,
Billing = Billing.ChargeAutomatically
};
var diffInvoice = await _stripeInvoiceService.CreateAsync(invoiceOptions);
// There's an alternative using Invoice Finalization, but this seems quicker
await _stripeInvoiceService.PayAsync(diffInvoice.Id, new InvoicePayOptions());