The January Problem
How do we deal with cloud vendor credits?
So, I’m solving “the January problem” today at my current employer, except that here it’s a February-March problem. To refresh our memory, this happens when you have a long term commitment with a cloud vendor that contains a provision for some kind of promotional credits to be applied to your bill. I’m not a fan of these credits but I understand why they exist and also that nobody cares what FinOps thinks about the arrangement. I’ve experienced this with two vendors so far - AWS and GCP - and they tend to make it rain on your bill to varying extents that can appear to zero out the cost of your bill on a cash basis. It looks basically like this:

This was not a hot button issue for me until lately when - yes, it can happen to you too! - some members of the engineering staff started asking me why some numbers they were looking at weren’t there for the last several days. I blamed Google but then a few days later remembered that it was that magical time of year.
I hacked around the missing data to get the reporting back up for a minute while I circled back to the real solution to this problem, which is to amortize those credits back into the bill. Here’s the general idea.
Rough methodology
It’s not really that tricky, but if you’ve never been an infrastructure person telling the Finance team how this is going to go, it can feel a little awkward at first. Here’s the methodology I recommend, at least as a conversation starter.
These credits are probably delivered to you on some kind of annual cycle (check your contract). This means that a 12 month amortization window is a reasonable choice. So here’s what might you do -
Sum up all of the promotional credits that you received at a monthly granularity going back as far as you’re able. Calculate a 12 month moving average of this number OR just divide this number by 12.
Sum up all of your costs excluding those credits at the same monthly granularity.
Divide the 12 month moving average by the monthly cost number to arrive at the “credit discount percentage”.
Discount your costs by that number monthly, et voila
Some visual examples, to make this a little more tangible.
Let’s say you have $600k in annual credits, and an average annual spend of $12M. That would zero out roughly 2 weeks of cloud costs, and otherwise inflate the remaining costs by approximately 5% over what they should actually be.
After amortizing that credit forward, and applying a discount percentage to your list cost you get a truer, smoother representation of the actual cost of your resources. Put another way - the yellow bars are the very spiky credits, where as the purple area is the 12 month average - 12m MA. In effect, the 12m MA is what you subtract from your monthly costs, and you put the transient credit data to the side. This resulting metric is what I call the “effective cost” around here.
To the SQL
We’ll use the GCP bill as the example here, since that’s what I’m working with. I handle this in two separate models, though you could conceivably handle this in a CTE in your GCP billing model. Ours is … voluminous, so I materialize all these queries as tables in DBT.
WITH source AS (
SELECT
invoice.month AS invoice_month,
seller_name,
-- The base charge before any credits are applied
cost,
-- Promotional credits only (annual service credits, BDR credits, POC credits, etc.)
-- These are the lump-sum credits we want to smooth out via amortization
(
SELECT SUM(CAST(amount AS NUMERIC))
FROM UNNEST(credits)
WHERE type = 'PROMOTION'
) AS credit_promotion_amount,
-- All other credits (CUDs, SUDs, discounts) — kept separate because these
-- reflect real negotiated pricing and should NOT be amortized away
(
SELECT SUM(CAST(amount AS NUMERIC))
FROM UNNEST(credits)
WHERE type != 'PROMOTION'
) AS credits_total_less_promotions
-- GCP billing export is pinned (each row lives in exactly one partition),
-- so a plain full-table scan is correct — no deduplication needed
FROM `your-billing-data.table`
),
monthly AS (
SELECT
invoice_month,
-- Flip to positive: credit amounts are negative in the export
ABS(SUM(COALESCE(credit_promotion_amount, 0))) AS monthly_promotional_credit,
-- Operational cost = what we'd pay Google without any promotional credits.
-- Formula: cost (net of all credits) + non-promo credits added back
-- = gross cost minus only the CUD/SUD/discount credits = pre-promo spend.
--
-- Third-party sellers (Marketplace) are excluded because they
-- never receive promotional credits, so including them would dilute the
-- discount factor and make it look smaller than it really is for Google spend.
SUM(
CASE
WHEN COALESCE(seller_name, 'Google') = 'Google'
THEN cost + COALESCE(credits_total_less_promotions, 0)
ELSE 0
END
) AS monthly_operational_cost
FROM source
GROUP BY invoice_month
),
final AS (
SELECT
PARSE_DATE('%Y%m', invoice_month) AS invoice_month,
monthly_promotional_credit,
monthly_operational_cost,
-- Rolling sum of promotional credits over the trailing 12 months
SUM(monthly_promotional_credit)
OVER (ORDER BY invoice_month ROWS BETWEEN 11 PRECEDING AND CURRENT ROW)
AS promotional_credit_trailing_12m_total,
-- Amortized monthly share: always divide by 12 (not the actual window size)
-- so that early months with a partial window aren't over-weighted
SUM(monthly_promotional_credit)
OVER (ORDER BY invoice_month ROWS BETWEEN 11 PRECEDING AND CURRENT ROW)
/ 12.0 AS avg_monthly_promotional_credit_trailing_12m,
-- Sanity-check: amortized credit as a % of that month's operational cost
ROUND(
SAFE_DIVIDE(
SUM(monthly_promotional_credit)
OVER (ORDER BY invoice_month ROWS BETWEEN 11 PRECEDING AND CURRENT ROW) / 12.0,
monthly_operational_cost
) * 100, 4
) AS promotional_credit_pct_of_operational_cost,
-- The multiplier to apply downstream:
-- amortized_cost = operational_cost * credit_adjustment_factor
-- A factor of 0.91 means ~9% of gross spend is covered by amortized credits
ROUND(
1 - SAFE_DIVIDE(
SUM(monthly_promotional_credit)
OVER (ORDER BY invoice_month ROWS BETWEEN 11 PRECEDING AND CURRENT ROW) / 12.0,
monthly_operational_cost
), 6
) AS credit_adjustment_factor
FROM monthly
)
SELECT * FROM final
ORDER BY invoice_month
And the entire routine, including the preceding query as a CTE:
WITH amortization AS (
-- Trailing 12-month average of promotional credits as a fraction of spend.
-- This smooths lump-sum credits (e.g. the ~$1.3M annual service credit applied
-- every Feb/Mar) evenly across all months so no single month looks artificially cheap.
SELECT
PARSE_DATE('%Y%m', invoice_month) AS invoice_month,
ROUND(
1 - SAFE_DIVIDE(
SUM(ABS(SUM(COALESCE(credit_promotion_amount, 0))))
OVER (ORDER BY invoice_month ROWS BETWEEN 11 PRECEDING AND CURRENT ROW) / 12.0,
SUM(SUM(CASE
WHEN COALESCE(seller_name, 'Google') = 'Google'
THEN cost + COALESCE(credits_total_less_promotions, 0)
ELSE 0
END)) OVER (ORDER BY invoice_month)
), 6
) AS credit_adjustment_factor
FROM (
SELECT
invoice.month AS invoice_month,
seller_name,
cost,
(SELECT SUM(CAST(amount AS NUMERIC)) FROM UNNEST(credits) WHERE type = 'PROMOTION')
AS credit_promotion_amount,
(SELECT SUM(CAST(amount AS NUMERIC)) FROM UNNEST(credits) WHERE type != 'PROMOTION')
AS credits_total_less_promotions
FROM `your-billing-data.table`
)
GROUP BY invoice_month
),
billing AS (
SELECT
PARSE_DATE('%Y%m', invoice.month) AS invoice_month,
seller_name,
service.description AS service_description,
sku.description AS sku_description,
cost,
(SELECT SUM(CAST(amount AS NUMERIC)) FROM UNNEST(credits))
AS credits_total,
(SELECT SUM(CAST(amount AS NUMERIC)) FROM UNNEST(credits) WHERE type != 'PROMOTION')
AS credits_total_less_promotions,
cost_at_list
FROM `your-billing-data.table`
)
SELECT
b.invoice_month,
b.service_description,
b.sku_description,
-- What Google charges before any discounts
SUM(b.cost_at_list) AS list_cost,
-- What we actually pay after CUDs, SUDs, and enterprise discounts
-- (but BEFORE promotional credits are applied)
SUM(b.cost + COALESCE(b.credits_total_less_promotions, 0)) AS operational_cost,
-- Operational cost spread across 12 months of promotional credit value.
-- Use this for COGS and unit cost calculations.
SUM(
(b.cost + COALESCE(b.credits_total_less_promotions, 0))
* a.credit_adjustment_factor
) AS effective_cost,
-- What actually appeared on the invoice (all credits applied, no smoothing)
SUM(b.cost + COALESCE(b.credits_total, 0)) AS billed_cost
FROM billing b
LEFT JOIN amortization a USING (invoice_month)
WHERE COALESCE(b.seller_name, 'Google') = 'Google'
GROUP BY 1, 2, 3
ORDER BY b.invoice_month, effective_cost DESC
The net result
Here is the result of smoothing those credits out - the big spikes are how they arrive and the purple area is how we incorporate them into our bill.
In closing
The January problem, regardless of when it visits your org, is really just a data quality problem in a finance costume. The credits and their savings are real, but the mismatch between when and how they land, and when you consume resources over the source of a year can wreck your reporting (once people actually start looking at it).
Amortization is not one they typically teach in technical curricula, but it’s a fact of life in Finance. Once you've had that conversation with Finance and gotten alignment on the methodology, you'll never have an engineering lead asking you why the numbers disappeared again.



