Last active
November 8, 2022 12:54
-
-
Save haacked/0a34391bfc2fddda192a082cfe5867af to your computer and use it in GitHub Desktop.
Calculating MRR with C# and the Stripe API
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This is the source for the blog post here: https://haacked.com/archive/2022/10/12/calculating-mrr-with-stripe-and-csharp/ | |
using System.Collections.Generic; | |
using System.Diagnostics; | |
using System.Linq; | |
using System.Threading.Tasks; | |
namespace Stripe; | |
public static class StripeExtensions | |
{ | |
public static decimal CalculateSubscriptionMonthlyRevenue(Subscription subscription) | |
{ | |
decimal revenue = 0; | |
foreach (var item in subscription.Items) | |
{ | |
var multiplier = item.Plan.Interval switch | |
{ | |
"day" => 30M, | |
"week" => 4M, | |
"month" => 1M, | |
"year" => 1M / 12M, | |
_ => throw new UnreachableException($"Unexpected plan interval: {item.Plan.Interval}.") | |
}; | |
revenue += multiplier * item.Quantity * item.Price.UnitAmountDecimal.GetValueOrDefault(); | |
} | |
return revenue / 100M; // The UnitAmount is in cents. | |
} | |
public static decimal CalculateCustomerMonthlyRevenue(Customer customer) | |
{ | |
var subscriptions = customer.Subscriptions; | |
var revenue = 0M; | |
foreach (var subscription in subscriptions) | |
{ | |
revenue += CalculateSubscriptionMonthlyRevenue(subscription); | |
} | |
// Apply the coupon, if any. We only look at % off coupons. | |
// We can ignore the amount off discount. That's a one time discount and doesn't affect ongoing MRR. | |
if (customer.Discount is { Coupon.PercentOff: { } percentOff }) | |
{ | |
revenue *= 1 - percentOff / 100M; | |
} | |
return revenue; | |
} | |
public static async Task<decimal> CalculateMonthlyRecurringRevenue() | |
{ | |
string? lastId = null; | |
var customerClient = new CustomerService(); | |
decimal revenue = 0M; | |
bool hasMore = true; | |
while (hasMore) | |
{ | |
var customers = await customerClient.ListAsync( | |
new CustomerListOptions | |
{ | |
Limit = 100, /* Max Limit is 100 */ | |
Expand = new List<string> { "data.subscriptions" }, | |
StartingAfter = lastId | |
}); | |
revenue += customers.Sum(CalculateCustomerMonthlyRevenue); | |
hasMore = customers.HasMore; | |
if (hasMore) | |
{ | |
lastId = customers.LastOrDefault()?.Id; | |
if (lastId is null) | |
{ | |
throw new InvalidOperationException("API reports more customers but no last id was returned."); | |
} | |
} | |
} | |
return revenue; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
"week" => 4M,
You should probably make this
52M / 12M
which gives you 4.333 weeks per month.