The dominant pricing pattern for modern platform-as-a-service products: customers pay a flat monthly fee that includes generous allowances of every metered resource, and overage charges kick in only when consumption exceeds the included quantity. The flat fee anchors the relationship and forecastability; the overage protects margin on heavy users and creates a natural upgrade path to the next tier.
Real-world examples. Vercel ($20/mo Pro tier with included bandwidth, builds, and serverless invocations; overage above), Supabase (per-project monthly fee with included database storage, auth users, edge function invocations), Render, PlanetScale, Upstash, Railway, Cloudflare Workers Paid. Common shape: one or two flat tiers with multiple included allowances per tier, real-time visibility into "how much of my allowance have I used", overage billed at the end of the period.
The shape of the problem
Hybrid pricing is harder than either pure flat or pure usage:
Allowance bookkeeping per metered dimension. A single subscription typically has 5-10 metered dimensions, each with its own included allowance and its own overage rate. Tracking remaining allowance accurately, in real time, across all of them is the core operational challenge.
Rollover policies. Some platforms let unused allowance roll over to the next period (encourages experimentation); others reset every cycle (encourages predictable forecasting). Both are legitimate; the policy must be expressible per-product, not hard-coded.
Tier upgrades mid-cycle. When a customer is about to blow past their allowance and upgrades to a higher tier, the upgrade should add the higher tier's allowance prorata, not double-bill the user for the period.
Overage transparency. Customers expect to see "$X.XX of overage so far this period" updating in real time; finance expects the period's invoice to land predictably at month end.
Free tier conversion. A free tier with capped allowance is the entry point - and the moment the customer crosses into paid usage is the conversion event finance wants tracked separately.
Kontier blueprint
Concern
Kontier primitive
Flat monthly fee
A DECLARED-quantity product priced per period on the plan
Per-dimension included allowance
included_quantity on each metered product's plan membership (POST /v1/plans/{id}/products)
Real-time allowance state
GET /v1/subscriptions/{id}/allowance
Rollover behavior
rollover_enabled per product on the plan + allowance.rolled_over webhook
Overage rates
Standard usage pricing on the same metered products, applied above the allowance
Tier upgrades mid-cycle
Cut the live revision now and continue on the higher plan's lines; the cut is prorated
Each metered product also needs a meter bound to it (POST /v1/meters, then POST /v1/products/{id}/meter-bindings with role: BILLABLE_QUANTITY); the API platform blueprint shows both calls.
included_quantity (a decimal string) is the quantity included per billing period. rollover_enabled: true carries unused allowance into the next period and emits allowance.rolled_over; rollover_max caps what carries and rollover_expiry_periods lets carried allowance lapse.
3. Set the prices (flat + overage rates)
Each price is scoped to the plan (plan_id); plan_version: 0 on a plan that has never been published stages it on the plan's working draft. The plan's price_cadence_unit (month here) is the period every amount covers.
Code
# Flat: $20/month for the platform tiercurl -X POST https://api.kontier.eu/v1/prices \ -H "Authorization: Bearer sk_test_…" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "product_id": "1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed", "plan_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "plan_version": 0, "currency": "USD", "list_price": "20.00" }'# Overage: $0.40/GB above the 1,000 GB allowancecurl -X POST https://api.kontier.eu/v1/prices \ -H "Authorization: Bearer sk_test_…" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "product_id": "2c5ea4c0-4067-11e9-8bad-9b1deb4d3b7d", "plan_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "plan_version": 0, "currency": "USD", "list_price": "0.40" }'# Overage: $0.20 per million invocations above the 10M allowance ($0.0000002 each;# a rate may carry up to 8 decimal places)curl -X POST https://api.kontier.eu/v1/prices \ -H "Authorization: Bearer sk_test_…" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "product_id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8", "plan_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "plan_version": 0, "currency": "USD", "list_price": "0.0000002" }'
The included quantity is consumed first; the overage price applies only above it. Then publish the products and the plan; each is a change:
The metered lines state nothing: their allowance and price come from the plan version they name. The first invoice is $20 flat. Overage charges only appear on invoices for periods when the customer exceeded an allowance.
billable_usage is the overage quantity the invoice line will carry if the period closed now. The customer-facing "78% of bandwidth used" widget reads directly from this endpoint.
6. Upgrade mid-cycle
The customer moves from Pro to a Team plan with larger allowances. Cut the live revision now, write the whole draft with a new phase on the Team plan's lines, and publish:
The cut answers draft revision 2: the Pro phase now ends at the cut instant (here 2026-11-20T15:05:00Z, read from phases[0].ends.at) and says then: "stop". Send it back as it is, with then: "next", and add the Team phase after it. The Team phase is a new plan, not the rest of the Pro phase, so it says "continues": false:
The cut instant is a billing boundary: an invoice written at the cut credits the Pro fee already billed for the rest of the period and bills the Team fee from the cut on. Publishing emits subscription.revision_published, and the cut's invoice follows within seconds (invoice.finalized).
Variations
Multi-tier ladder (Hobby / Pro / Team). Create one plan per tier with progressively larger allowances; an upgrade is the cut-and-continue in step 6. For "downgrade at end of period", cut at the end of the current period instead of now, or schedule it as a change (POST /v1/changes with subscription.transform); see Scheduling.
Pooled allowance across team members. When the platform charges per team rather than per developer, the allowance lives on the subscription (the team): usage events from all team members carry the same subscription_id and draw from one allowance.
One customer's allowance differs. Override the included quantity for one subscription with PUT /v1/subscriptions/{id}/products/{productId}/included-quantity, or grant extra usage with POST /v1/subscriptions/{id}/usage-credits; both show up in the allowance state.
Per-environment rates (prod vs preview). Make the metered products keyed, with one price per environment price_key (production, preview) and one subscription line per key.
Annual prepay with bonus allowance. Allowances live on the plan membership, not on prices, so model the annual deal as its own plan (price_cadence_unit: year) whose products carry a larger included_quantity.
What you don't have to build
Per-dimension allowance accounting (the plan membership's included_quantity does it)
Allowance-then-overage billing math (drawdown happens before the price is applied)
Rollover bookkeeping (allowance.rolled_over captures each rollover)
Real-time "X% of Y used" portal widget (GET /v1/subscriptions/{id}/allowance serves it)
Mid-cycle plan upgrades with proration (a cut is a billing boundary)
Conversion tracking (subscription.revision_published on every published revision)
Next steps
Plans - allowance and rollover configuration per plan version
Usage Metering - the event stream that consumes allowance