Reported September 2026
Stripesimulation

Subscription and Usage-Based Billing Calculator

Reported by candidates from Stripe's online assessment. Pattern, common pitfall, and the honest play if you blank under the timer.

Get StealthCoderRuns invisibly during the live Stripe OA. Under 2s to a working solution.
Founder's read

Stripe reported this billing calculator OA in September 2026, and the fixed input sizes are what make it feel harmless. It's a layered simulation: sum subscriptions per user, prorate mid-cycle changes, then add usage-based charges with flat and tiered pricing. Nothing here needs fancy algorithms. It needs clean structure, because each part extends the last and the problem text says so. If you blank on the proration math or the tier boundaries, StealthCoder runs invisibly during the live OA and gives you a working solution as a safety net. Read this first and you probably won't need it.

The problem

Stripe Billing helps companies like Figma, Notion, and Slack bill their customers for subscriptions, plan changes, and usage. For example, a customer might pay a fixed monthly subscription fee, upgrade their plan partway through the month, and accrue usage-based charges for API calls or storage. At the end of the month, Stripe consolidates all of those items into a single invoice, which helps reduce transaction costs and keeps billing simple for both the merchant and their customers.
In this problem, you'll build a simplified version of that billing engine. You'll start by computing monthly totals from fixed subscriptions, then add prorated charges for mid-cycle plan changes, and finally layer in usage-based billing with both flat and tiered pricing. Each section builds directly on the previous one, so take time to structure your code in a way that's easy to extend.
General Constraints and Assumptions:
All inputs are well-formed and valid.
All monetary amounts are in USD cents (e.g. 1000 = $10.00).
Billing cycles are exactly 30 days.
Subscription IDs are unique across all subscriptions.
A user may have multiple active subscriptions at the same time.
A user may have usage-based billing without any subscriptions.
Final charges are floored to the nearest cent right before charging the customer. (e.g. if a customer is to be charged $10.66666 for subscription_1 and $20.66666 for subscription_2, we expect the final charge to be floor(1066.666 + 2066.666) = 3133 (e.g. $31.33)
Changes may not be provided in chronological order.
The output should be a 2D string array where each inner array contains the user ID and their total charge as a string. e.g. ["user_1", "3500"].
Part 1 - Monthly Charges from Subscriptions
Given a list of subscriptions, write a function that returns the total monthly charge for each user.
Each subscription is represented as a comma-separated string with the following fields: user_id, subscription_id, monthly_cost, where monthly_cost is in USD cents. A user's total monthly charge is the sum of the monthly_cost values across all of their active subscriptions.
Example input:
subscriptions = [
"user_1,sub_a,1000",
"user_1,sub_b,2500",
"user_2,sub_c,500",
"user_2,sub_d,3000",
"user_2,sub_e,1500",
"user_3,sub_f,2000"
]
Example output:
[
["user_1", "3500"],
["user_2", "5000"],
["user_3", "2000"]
]
Part 2 - Monthly Charges with Mid-Month Subscription Changes
Customers do not always keep the same subscriptions for an entire billing cycle. They might upgrade, downgrade, or add new subscriptions partway through a month.
When a subscription changes mid-cycle, charges are prorated based on how many days each version was active. The billing cycle runs from day 1 to day 30, and all initial subscriptions start on day 1. Proration is calculated as: charge = monthly_cost * (days_active / 30)
The next captured portion begins mid-sentence:
start of day t, meaning it is active from its start day up to, but not including, day t. This can be calculated as days_active = change_day - start_day. The new subscription starts on day t and is tracked going forward. A subscription active through the end of the cycle has days_active = 31 - start_day.
You are given the same subscription list as before, plus a list of mid-cycle changes. Each change is represented as: user_id, old_subscription_id, new_subscription_id, new_monthly_cost, change_day
Example input:
subscriptions = [
"user_1,sub_a,1000",
"user_1,sub_b,2500",
"user_2,sub_c,500",
"user_3,sub_d,2000"
]
changes = [
"user_1,sub_a,sub_a_plus,1500,11",
"user_1,sub_a_plus,sub_a_pro,3000,21",
"user_2,sub_c,sub_c_premium,1200,16"
]
Example output:
[
[
"user_1",
"4333"
],
[
"user_2",
"850"
],
[
"user_3",
"2000"
]
]
Example calculation for user_1:
sub_a: 1000 * (10/30) = 333
sub_a_plus: 1500 * (10/30) = 500
sub_a_pro: 3000 * (10/30) = 1000
sub_b: 2500 * (30/30) = 2500
Total: 4333
Example calculation for user_2:
sub_c: 500 * (15/30) = 250
sub_c_premium: 1200 * (15/30) = 600
Total: 850
Example calculation for user_3:
sub_d: 2000 * (30/30) = 2000
Total: 2000
Part 3 - Monthly Charges with Mid-Month Subscription Changes and Usage-Based Billing
Only this Part 3 heading is visible; its section is collapsed in the source image. A Part 4 heading is partially cut off, and its contents are not visible.
FastPrep practice specification, added, not source wording
The text above preserves the wording visible in the source images. The source does not show the usage and tier schemas or callable interface. The following specification completes those missing details for the combined runnable exercise. It is an authored practice extension, not a transcription of the unseen parts.
Build a monthly billing calculator. Combine fixed subscriptions, prorated subscription changes, and usage charges for each user. Every billing cycle contains exactly 30 days, numbered 1 through 30. All money is expressed in USD cents.
Subscriptions
Each string in subscriptions has the format user_id,subscription_id,monthly_cost. These subscriptions are active from day 1. A user may have several subscriptions; subscription IDs are globally unique.
Mid-month changes
Each string in changes has the source format user_id,old_subscription_id,new_subscription_id,new_monthly_cost,change_day. On change_day, end the active old subscription and start the new subscription for the same user. Later changes may reference that new ID. Changes may arrive out of order.
Practice conventions for details not shown in the source: use - as old_subscription_id to add a subscription without replacing one. Otherwise the old ID must be active and belong to the given user. Every new ID is globally fresh, including IDs of retired subscriptions. Changes along one replacement chain have strictly increasing days; independent chains may change on the same day.
A version active from day a through day b, inclusive, contributes monthly_cost * (b - a + 1) / 30 cents. A change on day d ends the old version on day d - 1 and starts the new version on day d. The final version lasts through day 30.
Flat and tiered usage pricing
Each string in pricing has the format product_id,upper_bound,unit_price. Rows for one product define marginal pricing tiers and may be unordered. Positive upper bounds are distinct cumulative quantities. Exactly one row per product has upper bound -1, meaning no upper limit.
After sorting finite bounds, the first tier prices units 1 through its upper bound, the next tier prices units after that bound through its own upper bound, and so on. The unlimited tier prices all remaining units. A product with only an unlimited tier has a flat per-unit price. Each unit is charged at the price of its own tier; the final tier's price does not apply retroactively to earlier units.
Each string in usage has the format user_id,product_id,quantity. Sum quantities separately for each user-product pair before applying that product's tiers. Different users do not share tier allowances. Usage charges are independent of subscription changes. A user may have usage without a subscription.
Result
For each user mentioned in subscriptions, changes, or usage, add all subscription contributions and all usage charges, then floor the combined total once to the nearest cent. Do not round individual subscription segments or individual subscriptions. Include users whose total is zero.
Return a two-dimensional string array sorted lexicographically by user ID. Each row is [user_id, total_charge_as_string], with no currency symbol or decimal point. Return an empty array when there are no users.
Practice assumptions
For this exercise, assume pricing and usage records use the formats above; additions use the explicitly authored - convention, and same-day changes along one replacement chain are disallowed, and every used product has valid complete pricing tiers. Assume non-negative costs and quantities, zero-total users are included, and output rows are sorted by user ID.

Function
calculateMonthlyCharges(subscriptions: String[], changes: String[], pricing: String[], usage: String[]) → String[][]

Examples
Example 1
subscriptions = ["user_1,sub_a,1000","user_1,sub_b,2500","user_2,sub_c,500","user_2,sub_d,3000","user_2,sub_e,1500","user_3,sub_f,2000"]
changes = []
pricing = []
usage = []
return = [["user_1","3500"],["user_2","5000"],["user_3","2000"]]
This is the source monthly-subscription example. Sum the active costs for each user: 1000 + 2500 = 3500, 500 + 3000 + 1500 = 5000, and 2000.
Example 2
subscriptions = ["u1,s1,1000","u1,s2,2000"]
changes = ["u1,s1,s1_plus,2000,15"]
pricing = ["api,3,100","api,-1,50"]
usage = ["u1,api,2","u1,api,5"]
return = [["u1","4033"]]
The changed subscription contributes (14 * 1000 + 16 * 2000) / 30 cents; the other contributes 2000. Aggregate the usage to 7 units, costing 3 * 100 + 4 * 50 = 500. Floor the combined total: floor(106000 / 30 + 500) = 4033.
Example 3
subscriptions = ["u,s1,1000","u,s2,2000"]
changes = ["u,s2,s2_plus,3000,29", "u,s1,s1_plus,2000,29"]
pricing = []
usage = []
return = [["u","3133"]]
The two subscriptions contribute 32000 / 30 and 62000 / 30 cents. Floor only their combined charge: floor(94000 / 30) = 3133. Flooring them separately would incorrectly give 3132.
Example 4
subscriptions = ["user_1,sub_a,1000","user_1,sub_b,2500","user_2,sub_c,500","user_3,sub_d,2000"]
changes = ["user_1,sub_a,sub_a_plus,1500,11","user_1,sub_a_plus,sub_a_pro,3000,21","user_2,sub_c,sub_c_premium,1200,16"]
pricing = []
usage = []
return = [["user_1","4333"],["user_2","850"],["user_3","2000"]]
This is the source chained-change example. For user_1 the exact scaled total is 10*1000 + 10*1500 + 10*3000 + 30*2500 = 130000, so flooring once gives 4333. User_2 pays (15*500 + 15*1200)/30 = 850; user_3 pays 2000. The source displays the first segment as 333; retain its fractional value until final charging as required by General Constraints.

Constraints
All input records are well-formed and valid. Identifiers are nonempty strings containing only ASCII letters, digits, and underscores; the literal - is reserved for the authored addition convention in old_subscription_id.
For this exercise, assume the combined number of records across the four input arrays is at most 10^4. Every array may be empty.
1 ≤ change_day ≤ 30; 0 ≤ monthly_cost ≤ 10^9.
0 ≤ quantity ≤ 10^6; 0 ≤ unit_price ≤ 10^6.
Every finite tier bound is between 1 and 10^10. Each product has distinct finite bounds and exactly one unlimited tier.
Initial and new subscription IDs are globally unique. Replacements reference an active old ID owned by the same user. Days strictly increase along each replacement chain.
All totals and intermediates scaled by 30 fit in a signed 64-bit integer.

Reported by candidates. Source: FastPrep

Pattern and pitfall

The trick is hash maps plus careful ordering. Group subscriptions by user, then sort each user's changes by change_day, since they arrive out of order. Each change closes the old subscription at day t and opens the new one. The old one is active change_day - start_day days, and the final one is active 31 - start_day days. Brute force isn't the risk. Rounding is. Keep every charge as an unrounded value and floor only once, on the user's total, not per subscription. Floor early and you'll be off by a cent on the example with 4333. Use exact fractions or multiply everything by 30 and divide at the end to avoid float drift. Also handle users who have usage but no subscriptions. For tiered pricing, charge each unit band at its own rate rather than pricing all units at the top tier. If you freeze mid-Stripe, StealthCoder is the hedge for the live OA.

Drill it cold or hedge it with StealthCoder. Either way, don't walk into the OA hoping you remember the trick.

If this hits your live OA

You can drill Subscription and Usage-Based Billing Calculator cold, or you can hedge it. StealthCoder runs invisibly during screen share and surfaces a working solution in under 2 seconds. The proctor sees the IDE. They don't see what's behind it. Made for the candidate who got the OA invite this morning and has 72 hours, not six months.

Get StealthCoder

Related leaked OAs

⏵ The honest play

You've seen the question. Make sure you actually pass Stripe's OA.

Stripe reuses patterns across OAs. Made for the candidate who got the OA invite this morning and has 72 hours, not six months. Works on HackerRank, CodeSignal, CoderPad, and Karat.

Subscription and Usage-Based Billing Calculator FAQ

How hard is the Stripe billing calculator OA really?+

The algorithms are easy. It's hash maps, sorting, and arithmetic. The difficulty is staying organized across three parts that build on each other, and getting the rounding exactly right. Candidates lose points on off-by-one day counts and flooring too early, not on complexity.

What's the trick to proration here?+

Sort each user's changes by change_day, then walk the chain. The old subscription gets change_day - start_day days, the new one starts at change_day. The last one gets 31 - start_day days. Multiply monthly_cost by days over 30, and don't round yet.

When do I floor the charge?+

Once, at the very end, on each user's total. The problem gives an example where two subscriptions at 1066.666 and 2066.666 sum to 3133. Flooring each one separately gives 3132. Keep fractional values, or scale by 30, until the final step.

How should I structure the code for three parts?+

Write small functions: one to parse subscriptions, one to apply changes, one to compute usage. Keep a per-user running total as a number, not a string. The statement says each section extends the last, so avoid hardcoding things you'll need to modify in part two or three.

How do I prepare in 48 hours?+

Practice parsing comma-separated strings into maps, sorting events by a day field, and computing tiered pricing with bands. Then write the full pipeline once on the examples in the statement. Check that your outputs match 4333 and 850 before anything else.

Problem reported by candidates from a real Online Assessment. Sourced from a publicly-available candidate-aggregated repository. Not affiliated with Stripe.

OA at Stripe?
Invisible during screen share
Get it