How the premium gets calculated
Every quote starts from a tariff rate, passes through thirteen independent loading factors, gets grossed up once, then has every applicable discount subtracted — with a floor check at the end that can claw discounts back if the result lands below the allowed minimum. This is the plain-language walkthrough of that pipeline, with a worked example at real magnitude.
One pipeline, four stages
Unlike the Medical rate engine, Motor Comprehensive doesn't blend two independent rates — it's a single linear pipeline. A tariff rate is selected, loaded up with rating factors, grossed up once, discounted, and finally checked against a minimum-premium floor that can push back on either the discounts or the premium itself.
%%{init: {'theme':'base', 'themeVariables': {'primaryColor':'#e6eef4','primaryBorderColor':'#1c5f8a','primaryTextColor':'#1c5f8a','lineColor':'#8a8272','fontFamily':'Georgia, serif','fontSize':'14px'}}}%%
flowchart TD
A["Basic Tariff
rate selected by product/scheme/vehicle/region,
compared against a TPL floor and a tariff minimum"]:::book
B["13 Loading Factors
Gender · Marital · Insured Age · Nationality · Body Type ·
City · Profession · Usage · Region · Deductible · Repair Type · NCD · Sum Insured
(+ conditional Accident Loading)"]:::book
C["NRP → Gross
one Applicable-Loading gross-up"]:::book
D["Discounts
NCD · Scheme/User · Loyalty · Driver ·
Promo · Other · Entity"]:::exp
E["Minimum-Premium Floor
NetGross checked against the cached floor"]:::floor
F["Final Premium
one row per deductible option"]:::final
A --> B --> C --> D --> E --> F
classDef book fill:#e6eef4,stroke:#1c5f8a,color:#1c5f8a,stroke-width:1.5px
classDef exp fill:#f6ecdd,stroke:#a8621a,color:#a8621a,stroke-width:1.5px
classDef floor fill:#f1e7f5,stroke:#7a3b8f,color:#7a3b8f,stroke-width:1.5px
classDef final fill:#201c16,stroke:#201c16,color:#f7f4ec,stroke-width:1.5px
The whole pipeline runs once per deductible option on the product — the API returns a list, one row per deductible, so the caller can show the customer several excess levels side by side.
Thirteen independent loadings
Every loading is a percentage of the Basic Premium, looked up independently and added on top — none of them compound against each other, they all apply to the same base figure.
| Factor | Keyed by | Notes |
|---|---|---|
| Gender | Insured's gender code | |
| Marital Status | Insured's marital status code | |
| Insured Age | Insured's age (range match) | Netted against Driver Age Loading later — see §3 |
| Vehicle Nationality | Vehicle's nationality-of-make code | |
| Body Type | Vehicle type code | |
| Registration City | Vehicle registration city code | |
| Profession | Insured's profession/occupation code | |
| Vehicle Usage | Usage code (private, commercial, …) | |
| Region | Vehicle registration region code | |
| Deductible | The deductible option being priced | One value per row in the result list |
| Repair Type | Agency vs. non-agency repair | |
| NCD (loading) | Claim-free years | Distinct from the NCD discount applied later — see §5 |
| Sum Insured | Sum Insured band |
Conditional — Accident Loading
Only evaluated when the request carries at least one prior accident (NoOfAccidents > 0). The match is resolved by priority, exact values beating wildcards in this order: Product, then Source (Aggregator / Online / POS vs. "All"), then Vehicle Usage — mirroring how the same loading is resolved server-side in the SP.
One gross-up, from NRP to Gross
A single "Applicable Loading %" — the product's own margin/expense load — grosses NRP up into the Gross premium. This is the figure every discount in the next section is subtracted from.
Every discount comes off Gross
Each discount is its own percentage of Gross, and they're all subtracted independently — order doesn't compound them, they're all computed against the same Gross figure.
| Discount | Source | Notes |
|---|---|---|
| NCD (No-Claims Discount) | Claim-free years | Separate from the NCD loading in §3 |
| Scheme / User | Scheme-level discount, falling back to a per-user discount if the scheme has none | |
| Loyalty | Only if the request flags IsLDApplicable | Caller determines eligibility upstream — see §8 |
| Driver | Only if the request flags a qualifying female driver | |
| Promo | Passed directly in the request | Caller supplies the % |
| Other | Passed directly in the request | Caller supplies the % |
| Entity | Passed directly in the request | Caller supplies the % |
Driver Age Loading — netted, not stacked
A separate age-based loading tied to the driver's minimum age is looked up and applied against (Gross − NCD − Loyalty). To avoid charging twice for the same "young driver" risk that the Insured-Age loading in §3 may have already priced in, the Insured-Age loading amount is subtracted from it — and if that leaves nothing, no additional charge is made at all:
Putting it together
Figures below are illustrative, not real tariff data — chosen to show the mechanics at a realistic order of magnitude for a mid-range comprehensive policy.
Tariff Rate = 2.1% → Base Premium = 2.1% × 500,000 = 10,500.00
TPL Floor comparison: TPL Basic 950 + 10% config = 1,045.00 (lower, ignored)
Tariff Minimum Premium = 900.00 (lower, ignored)
Final Basic Premium (BasePremium wins) = 10,500.00
Loadings (of 10,500.00):
Marital Status 3% → 315.00
Insured Age 15% → 1,575.00
City 1% → 105.00
Region 2% → 210.00
Repair Type 8% → 840.00
(Gender, Nationality, Body Type, Profession, Usage,
Deductible, Sum Insured, NCD-loading, Accident — all 0% in this example)
Loadings total = 3,045.00
NRP = 10,500.00 + 3,045.00 = 13,545.00
Applicable Loading % = 10%
Gross = 13,545.00 ÷ (100 − 10) × 100 = 15,050.00
Discounts (of 15,050.00):
NCD (5 claim-free years) 20% → 3,010.00
Scheme/User discount 5% → 752.50
(Loyalty, Driver, Promo, Other, Entity — not applicable here)
NetGross = 15,050.00 − 3,010.00 − 752.50 = 11,287.50
Driver Age Loading check:
Raw charge = (15,050.00 − 3,010.00) × 5% = 602.00
Insured-Age loading already charged = 1,575.00
Raw charge < Insured-Age amount → Driver Age Loading applied = 0.00
Minimum-premium floor for this cell = 9,000.00
NetGross (11,287.50) is above the floor → no reverse calculation triggered
FINAL PREMIUM = 11,287.50
Gross (unchanged) = 15,050.00 NCD 45% → 6,772.50 | Scheme/User 5% (non-adjustable) → 752.50 NetGross = 15,050.00 − 6,772.50 − 752.50 = 7,525.00 Minimum-premium floor = 9,000.00 7,525.00 < 9,000.00 → reverse calculation triggers Gross − NonAdjustable (Scheme/User 752.50) = 14,297.50, which is still above the 9,000.00 floor → Case 1 applies (shrink NCD, not gross-up) MaxAdjustableDiscAmt = 14,297.50 − 9,000.00 = 5,297.50 AdjDiscVal = 5,297.50 ÷ 45% = 11,772.22 New NCD% = (45% × 11,772.22) ÷ 15,050.00 × 100 ≈ 35.20% New NCD amount = 15,050.00 × 35.20% ≈ 5,297.60 FINAL PREMIUM ≈ 15,050.00 − 5,297.60 − 752.50 ≈ 9,000.00 ← lands on the floor
What this pipeline doesn't cover yet
This engine was built to remove per-request database load from quoting. Additional Covers and VAT are now implemented (2026-07-30) — see §9 for what's priced and what's deliberately excluded. What's left, in full detail in Project Details.md:
Additional Covers — every eligible non-basic cover (Personal Accident, Replacement Vehicle, Zero Depreciation, etc.) is now priced alongside the base premium, gated by an eligibility whitelist per vehicle. Geographic-extension covers and Replacement Cover are intentionally excluded — production's own live quote flow doesn't exercise them either.
VAT — a flat per-product rate (currently 15% for Motor Comp) is now applied to both the base premium and every additional cover.
- Comprehensive premium CAP (a maximum-premium ceiling for certain vehicle/product combinations) is not applied — verified dormant (zero active rows) as of this review, so not a launch blocker.
- Cross-Sell and Multi-Vehicle discounts require a live lookup of the customer's existing policies — they're structurally hard to pre-cache and are currently not computed.
- Motor Scheme Discount cap (a ceiling on the combined total of all discounts) is not enforced, so heavily-discounted quotes could combine discounts beyond what a scheme actually allows.
- Loyalty, Promo, Other, and Entity discounts are taken as given by the caller rather than independently verified server-side, unlike in the production procedure.
Pricing the optional covers
Computed once per deductible option, right after that row's own Gross and minimum-premium floor are final — matching how production sources the Gross figure it prices add-ons from.
| Pricing type | How Gross is derived |
|---|---|
| Fixed | A flat rate, or Rate × Passenger Seats for per-seat covers (Personal Accident Benefit) |
| Applicable at Cover level | Rate looked up by Region × Body Type × Nationality × Vehicle Group × Usage × Deductible-band × Insured-Age-band × Manufacture-Year-band, then Rate × Gross ÷ 100 (or a flat minimum, or per-seat, depending on the cover) |
A non-mandatory cover is only offered if an active eligibility rule exists for this vehicle's Make/Model/Body Type/Nationality/Vehicle-Age/Deductible-band — otherwise it's silently left off the list, exactly as production does. Mandatory covers bypass this check entirely.
Fixed 2026-07-30: the Deductible-band check above must compare against a real deductible amount, not just a code. It was initially resolving that amount from the request's own DeductableCode field — which is 0 whenever a caller asks for every deductible option at once, causing deductible-banded covers (e.g. Personal Accident Benefit — Driver/Passenger) to silently disappear. Each returned premium row already carries its own resolved deductible code from its matched tariff row, so Additional Covers now price off that instead — correctly, for every deductible option in the response, not just a single caller-specified one. Every additional cover now also carries its own DeductableCode so it's traceable which option it belongs to.
Formula reference
| Stage | Formula | Notes |
|---|---|---|
| Final Basic Premium | MAX(Rate × SumInsured ÷ 100, TPL Floor, Tariff MinPremium) | TPL Floor = TPL Basic × (1 + MinPremiumConfig%) |
| NRP | Basic Premium + Σ(Basic Premium × Loading%) | 13 independent loading factors, see §3 |
| Gross | NRP ÷ (100 − Applicable Loading%) × 100 | Single product-level gross-up |
| NetGross | Gross − NCD − Loyalty − User/Scheme − Driver − Promo − Other − Entity | All discounts computed independently off Gross |
| Driver Age Loading | MAX(0, (Gross−NCD−Loyalty)×Rate% − Insured-Age Loading Amount) | Prevents double-charging young-driver risk |
| Min-Premium shrink | AdjDiscVal = (Gross − NonAdjDisc − MinPremium) ÷ Σ AdjustableDisc% | Only if shrinking discounts alone can reach the floor |
| Min-Premium gross-up | RevCalLoadAmt = MinPremium ÷ (100 − TotalDiscPer) × 100 − Gross | Used only when shrinking discounts to zero still isn't enough |