What-if pricing — the rate preview over real usage
Pricing decisions fail on one of two axes: either the proposed rate set is wrong, or it is right on paper but wrong for your specific traffic mix. Devotel Orbit’s what-if pricing simulator exists to close the second failure: it replays the usage events your organization already recorded through a candidate rate card and tells you what those exact messages and minutes would have cost. The traffic is held fixed; only the rates move. This page builds the model — what a usage lane is, what a candidate card is, how the two meet — so the step-by-step guide has an anchor and the neighboring preview surfaces stay in their own lanes.What the preview answers — and what it never does
The simulator answers one question: projected spend, and the signed delta, if a candidate rate set were applied to your historical usage. Nothing else moves:- It is not a traffic-mover. A preview emits no send, touches no provider, and routes nothing. The usage it reads is already recorded; the replay is a report over your own history.
- It is not a rater. No charge is computed against your wallet, no invoice line appears, no pricing override changes. Applying a rate for real is a different surface — Pricing and rate resolution — that owns the precedence rules a live send is actually charged under.
- It is your data, not a catalog. The baseline comes from your own recorded usage under your own live rates, resolved with the same pricing ladder your invoice uses. A tenant with no recorded traffic gets an all-zero simulation, not an error.
The usage-lane taxonomy
Everything starts from the usage records your organization accumulates as it sends — each send logs its event type, destination, direction, and quantity. A single preview call aggregates those records into lanes — the simulator’s unit of comparison. A lane is:- event_type maps to a billing channel: messaging usage is recorded as
<channel>_sent(sms_sent,whatsapp_sent), voice usage asvoice_minute. Meters a per-unit rate card cannot re-price — recording, embeddings, AI-agent conversations — are skipped entirely. - country_code is the normalized upper-case ISO alpha-2 destination, with a missing value grouping under the
*wildcard. - direction collapses inbound spellings (
mo,inbound,in) tomo; everything else ismt(outbound). - sub_type carries finer partitions such as WhatsApp’s
marketing/utility; empty values group undernull.
The lane cap and the overflow rule
One simulation replays at most 200 distinct lanes (WHATIF_MAX_LANES), cutting by descending quantity. If your traffic mix produces more lanes than that, the tail is not silently lost — it is excluded by rank, which is exactly why the guide tells you to read the lane list before the totals: lanes outside the cut never reach the response, so their cost is in neither the current nor the candidate total. A preview over a wide country mix is a projection of your top 200 lanes, and the totals are honest about that scope.
Candidate rates — the partial override
The request body carries acandidate_card: an array of rate rows with per-lane scope. Each row pairs a lane key (channel, country_code, direction, sub_type) with a price:
rate_per_unit— the wholesale base, USD per unit (per message, per voice minute). Values are USD — not cents — at this layer; the simulator converts to cents with sub-cent precision internally.markup_bps— optional proportional markup in basis points (500= 5%), layered on the base.markup_fixed_cents— optional flat per-unit markup in cents.absolute_price_cents— optional fixed per-unit price in cents; when set, it replaces the base-plus-markup math entirely.
candidate_matched: false with zero delta. You model only the lanes you intend to change, and the simulation total moves only for those.
When several rows could price one lane, the same most-specific-wins ladder your live rate resolution uses decides: an org-independent exact country beats the * wildcard; an exact sub-type beats a sub-type-agnostic row; direction must match (mt rows never re-price mo lanes). Ties resolve to the first row in array order. Because the simulator reuses the live resolver’s naming and math, a candidate card you like can be expressed later as real overrides without the semantic drift two different calculators would hand you.
Reading the response — lanes, then totals
Every preview response has the same shape:window_days, your echoed label, a lanes array, and a rolled-up totals object.
Per lane you get the quantity, both per-unit prices and both totals, the candidate_matched coverage flag, and the signed delta_cents / delta_percent (null when the current cost is zero but the candidate is not). All money is USD cents; unit prices carry sub-cent precision, totals are whole cents rounded up once per lane — the never-under-bill convention your invoice also uses.
The totals roll the lanes up: current_total_cents, candidate_total_cents, the signed delta_cents and delta_percent, plus two coverage counters that matter more than the delta does: lane_count and matched_lane_count. A card that matches 1 of 40 lanes gives you a projection about one lane — delta_percent on the totals is only meaningful once its coverage is confirmed against the lane count.
The dashboard surface — Billing → What-if pricing simulator — renders this same comparison interactively (a per-channel editable rate plus a global ±% slider, rolled up to one row per channel). Both the dashboard and POST /api/v1/billing/whatif-pricing/preview are gated to the owner, admin, or billing role, because the reply exposes your real per-channel spend.
The boundary — previews never mutate billing
A what-if preview is a read with arithmetic attached. It writes no row, emits no event, moves no money, and leaves your live rates, overrides, and invoice untouched no matter what you model. A candidate rate takes effect only when it is installed as a real rate override — at which point Pricing and rate resolution owns the precedence and the audit trail. The simulator’s job ends at the projection; resolution’s job starts there.Which preview do I open?
Orbit ships several read-only “what would this cost” surfaces, and they answer different questions. Anchor them:
Decision box:
- Negotiating a rate card, plan, or volume tier against your own real traffic → what-if pricing.
- Projecting margin or partner payout economics → the billing pricing previews.
- Asking which route a specific send would take → the LCR route quote.
Worked sample — a candidate US SMS rate against 30 days
Back-test a negotiated SMS rate for outbound US traffic against your last 30 days:matched_lane_count: 1 of lane_count: 1 says the card covered the whole scope of this window’s US MT SMS lane, and delta_cents: -513 is what the candidate rate set would have saved on that traffic — 3,420 messages re-priced from 22.23. A negative delta green-lights the rate; a positive one prices the trade-off before you sign.
See also
- What-if pricing simulator guide — the step-by-step how-to for the dashboard and the API.
- Pricing and rate resolution — how a rate actually takes effect: precedence, overrides, and the path from resolution to the wallet ledger.
- Pricing calculator — the dashboard estimator widgets for channel, RTC, AI, and reseller payout projections.
- Least-cost routing — the route-choice layer the LCR quote previews.