How weighted_sum bills storage, and why you must send deltas not totals

Last updated: June 29, 2026

If your storage usage in Lago looks wildly larger than the actual storage you have, the most common reason is that the weighted_sum aggregation expects each event to carry the change in value since the last event (a delta), not a snapshot of the current total. Sending the daily total as the event value makes Lago treat each total as an additional increase on top of the previous total, so the running level explodes. The aggregation is time-weighted over the billing period, so a level that ratchets up every day compounds into a huge number.

How weighted_sum is calculated

Weighted_sum keeps a running total. Each event's value is added to that running level, and the running level is weighted by how long it stayed at that level before the next event, divided by the full billing period in seconds. In words, for each interval: contribution = cumulative_level × seconds_at_that_level / period_seconds, summed across the period. Two details matter:

  • The value is a delta. To represent storage of a, then b, then c, you send a, then b - a, then c - b. Sending a, b, c as raw totals overcounts because each is added to the running level.

  • The denominator is the whole billing period. Lago divides by the full billing period in seconds, not by the elapsed time between your events. A common reason a hand-rolled calculation disagrees with Lago is using elapsed seconds between events instead of the full period.

How to confirm whether totals or deltas were sent

Compare your event values against your known storage curve. If each day's event value roughly equals that day's absolute storage (rather than the day-over-day change), you are sending totals into a delta-based metric, which is the overcount. You can reproduce Lago's figure by building a timeline of deltas, accumulating the level, and weighting each level by its duration over the full period seconds. If your reproduction matches the UI only when you feed raw totals, that confirms totals were sent.

Choosing the right approach for storage

Depending on how you want to bill storage that changes over time, different aggregations fit:

  • Track the peak: if you only want the maximum storage in the period, use the MAX aggregation, which takes the highest value you send and does not require deltas.

  • Time-weighted accumulation: if you genuinely want storage summed across the time it sat at each level, weighted_sum is correct, but you must send deltas and the first event of the period carries the absolute starting value.

  • Average over the period: Lago does not offer a built-in average or weighted-average aggregation. A practical workaround uses two metrics: a non-invoiceable sum metric that accumulates daily totals, and a second metric using the latest aggregation that you feed a computed running average (total divided by days elapsed) once per day. The latest value at billing time becomes the charge.

Getting the billing period boundaries

If you compute a per-day value and emit it the next day, the subscription will already report the new period's start, not the period you are closing out. Use the get past usage endpoint with the external customer ID and external subscription ID to read the previous period's from_datetime and to_datetime. For anniversary billing where the anniversary day does not exist in a given month (such as the 31st), Lago clamps to the last day of that month.


This article reflects guidance drawn from customer case resolutions. It is not officially supported documentation and may not apply to all situations.