Underwriting Workflow¶
Implementing automated underwriting rules and decision-making.
Complete Underwriting Function¶
fn UnderwriteQuote(customer, items, premium) {
// 1. Age validation
if (customer.Age < 18) {
$Decline("Applicant must be 18 or older");
return "Declined";
}
if (customer.Age > 80) {
$Level2Referral("Applicant age over 80 - requires senior review");
return "Referred";
}
// 2. Claim history
if (customer.ClaimCount > 5) {
$Decline("Excessive claim history - unacceptable risk");
return "Declined";
}
if (customer.ClaimCount >= 3) {
$Level1Referral(customer.ClaimCount + " previous claims - requires assessment");
return "Referred";
}
// 3. High value items
let highValueItems = $Filter(items, fn(item) => item.Value > 5000);
if ($Count(highValueItems) > 0) {
$Level2Referral("High value items require valuation");
for (let item in highValueItems) {
$AddEndorsement("VAL" + item.Id, "Proof of value required for " + item.Name);
}
return "Referred";
}
// 4. Premium thresholds
if (premium > 25000) {
$Level3Referral("Premium exceeds £25,000 - senior approval required");
return "Referred";
}
if (premium > 10000) {
$Level2Referral("Premium exceeds £10,000 - manager approval required");
return "Referred";
}
// 5. Security requirements
if (customer.SecurityLevel < 3) {
$AddEndorsement("SEC01", "BS3621 locks required on all external doors");
$AddEndorsement("SEC02", "Burglar alarm required - certificate of installation needed");
}
// 6. Professional use
if (customer.ProfessionalUse) {
$Level1Referral("Professional use declared - requires review");
$AddEndorsement("EX01", "Business use excluded unless specifically agreed");
}
// 7. Territory risk
if (customer.TerritoryRisk == "HIGH") {
$Level1Referral("High risk postcode - enhanced security required");
$AddEndorsement("SEC03", "24-hour monitored alarm system required");
}
// Accept if no issues
$AddUnderwriterDecision("Accept", "Standard risk - auto-accepted", "NoAuthority");
return "Accepted";
}
Integration with Quote Process¶
// Complete quote with underwriting
fn ProcessCompleteQuote() {
// 1. Calculate premium
$SetCurrencyToPricingMatrix("GBP");
$SetCommissionRateToPricingMatrix(0.15);
$SetIptRateToPricingMatrix(0.12);
let age = $CalculateAge($Today(), Customer.DateOfBirth);
let basePremium = 450.00;
if (age < 25) { basePremium = 600.00; }
else if (age > 70) { basePremium = 550.00; }
$AddItemToPricingMatrix("Contents Cover", basePremium, 1.0);
if (Customer.NoClaimsYears >= 3) {
$AddFactorToPricingMatrix("No Claims Discount", 0.90, true, 0);
}
$SetFeeToPricingMatrix(25.00);
$CalculatePremiumAdditive("NewBusiness");
// 2. Run underwriting
let uwDecision = UnderwriteQuote(Customer, Items, PricingMatrix.Premium);
// 3. Build response based on decision
let response = {
Premium: PricingMatrix.Premium,
MonthlyPayment: Output.Monthly.MonthlyPayment,
Decision: uwDecision,
Endorsements: Endorsements
};
// Check for decline
let declined = $FindEquals(UnderwriterDecisions, "Decision", "Decline");
if (declined != null) {
response.DeclineReason = declined.Message;
return response;
}
// Check for referrals
let referrals = $Filter(UnderwriterDecisions, fn(d) => $Contains(d.Decision, "Referral"));
if ($Count(referrals) > 0) {
response.ReferralReasons = $Map(referrals, fn(r) => r.Message);
response.RequiresManualReview = true;
}
return response;
}
let quoteResult = ProcessCompleteQuote();
if (quoteResult.Decision == "Declined") {
$Log("Quote declined: " + quoteResult.DeclineReason);
} else if (quoteResult.Decision == "Referred") {
$Log("Quote referred for review");
for (let reason in quoteResult.ReferralReasons) {
$Log("- " + reason);
}
} else {
$Log("Quote accepted - Premium: £" + $ToString(quoteResult.Premium));
}
Risk-Based Underwriting¶
fn CalculateRiskScore(customer, items) {
let riskScore = 100; // Start at baseline
// Age risk
if (customer.Age < 25) { riskScore = riskScore + 30; }
else if (customer.Age > 75) { riskScore = riskScore + 20; }
// Claim history risk
riskScore = riskScore + (customer.ClaimCount * 15);
// High value items risk
let highValueCount = $Count($Filter(items, fn(i) => i.Value > 3000));
riskScore = riskScore + (highValueCount * 10);
// Security risk
if (customer.SecurityLevel < 3) { riskScore = riskScore + 25; }
// Territory risk
if (customer.TerritoryRisk == "HIGH") { riskScore = riskScore + 40; }
else if (customer.TerritoryRisk == "MEDIUM") { riskScore = riskScore + 15; }
// No claims bonus
if (customer.NoClaimsYears > 5) { riskScore = riskScore - 20; }
return riskScore;
}
fn UnderwriteByRiskScore() {
let riskScore = CalculateRiskScore(Customer, Items);
$Log("Risk Score: " + $ToString(riskScore));
if (riskScore > 200) {
$Decline("Risk score " + $ToString(riskScore) + " exceeds acceptable threshold");
} else if (riskScore > 150) {
$Level2Referral("High risk score: " + $ToString(riskScore) + " - requires assessment");
} else if (riskScore > 120) {
$Level1Referral("Elevated risk score: " + $ToString(riskScore));
} else {
$AddUnderwriterDecision("Accept", "Risk score within acceptable range: " + $ToString(riskScore), "NoAuthority");
}
}
Territory-Based Rules¶
fn UnderwriteTerritory(postcode) {
let territoryRisk = DetermineT erritoryRisk(postcode);
if (territoryRisk.Level == "UNACCEPTABLE") {
$Decline("Territory risk unacceptable - postcode " + postcode);
return;
}
if (territoryRisk.Level == "HIGH") {
// High risk area requirements
if (Customer.SecurityLevel < 5) {
$Decline("Insufficient security for high-risk territory");
return;
}
$AddEndorsement("TER01", "Property located in high-risk area");
$AddEndorsement("SEC05", "24-hour monitored alarm system mandatory");
$Level2Referral("High risk territory - enhanced security confirmed");
} else if (territoryRisk.Level == "MEDIUM") {
// Medium risk area
if (Customer.SecurityLevel < 3) {
$Level1Referral("Security below standard for medium-risk area");
}
$AddEndorsement("SEC01", "BS3621 locks required on all external doors");
}
// Low risk areas - no additional requirements
}
Claim History Analysis¶
fn AnalyzeClaimHistory(claims) {
if ($Count(claims) == 0) {
$Log("No claim history - positive indicator");
return { Accept: true, Factor: 0.90 }; // 10% discount
}
// Recent claims (last 3 years)
let recentClaims = $Filter(claims, fn(c) =>
$DifferenceInDays($Today(), c.Date) <= 1095 // 3 years
);
if ($Count(recentClaims) > 2) {
$Level1Referral($ToString($Count(recentClaims)) + " claims in last 3 years");
return { Accept: true, Factor: 1.30 }; // 30% loading
}
// High value claims
let highValueClaims = $Filter(claims, fn(c) => c.Amount > 5000);
if ($Count(highValueClaims) > 0) {
$Level1Referral("Previous high value claim(s) - £" + $ToString($Sum($Map(highValueClaims, fn(c) => c.Amount))));
}
// Fraud indicators
let fraudIndicators = $Filter(claims, fn(c) => c.FraudFlag == true);
if ($Count(fraudIndicators) > 0) {
$Decline("Previous fraud indicators on claim history");
return { Accept: false };
}
return { Accept: true, Factor: 1.05 }; // Small loading for claims
}
Endorsement Management¶
fn AddStandardEndorsements(customer, items) {
// Alarm requirement for high values
let totalValue = $Sum($Map(items, fn(i) => i.Value));
if (totalValue > 30000) {
$AddEndorsement("SEC04", "Approved burglar alarm required - NSI/SSAIB Gold standard");
}
// Single item limits
let maxSingleItem = $Max($Map(items, fn(i) => i.Value));
if (maxSingleItem > 10000) {
$AddEndorsement("LIM01", "Single item limit: £" + $ToString(maxSingleItem) + " - valuation required");
}
// Professional use exclusion
$AddEndorsement("EX02", "Professional, business, or trade use excluded");
// Standard exclusions
$AddEndorsement("EX03", "War, terrorism, and nuclear risks excluded");
$AddEndorsement("EX04", "Unoccupied property exclusion - notify if property unoccupied >30 days");
}
Complete Example¶
// Full underwriting workflow
fn ProcessQuoteWithUnderwriting() {
// Customer data
let Customer = {
Age: 42,
DateOfBirth: $ToDate("1981-08-15"),
ClaimCount: 1,
NoClaimsYears: 4,
SecurityLevel: 4,
TerritoryRisk: "MEDIUM",
ProfessionalUse: false,
PostCode: "SW1A 1AA"
};
let Items = [
{ Id: 1, Name: "Jewelry", Value: 8000 },
{ Id: 2, Name: "Art", Value: 12000 },
{ Id: 3, Name: "Electronics", Value: 5000 }
];
// Calculate premium
$SetCurrencyToPricingMatrix("GBP");
$SetCommissionRateToPricingMatrix(0.15);
$SetIptRateToPricingMatrix(0.12);
let basePremium = 650.00; // Based on total value
$AddItemToPricingMatrix("High Value Contents", basePremium, 1.0);
if (Customer.NoClaimsYears >= 3) {
$AddFactorToPricingMatrix("No Claims Discount", 0.90, true, 0);
}
$SetFeeToPricingMatrix(25.00);
$CalculatePremiumAdditive("NewBusiness");
// Underwriting
let uwDecision = UnderwriteQuote(Customer, Items, PricingMatrix.Premium);
// Add standard endorsements
AddStandardEndorsements(Customer, Items);
// Territory-specific rules
UnderwriteTerritory(Customer.PostCode);
// Build final response
return {
Decision: uwDecision,
Premium: PricingMatrix.Premium,
Monthly: Output.Monthly.MonthlyPayment,
Endorsements: Endorsements,
UnderwriterDecisions: UnderwriterDecisions
};
}
let result = ProcessQuoteWithUnderwriting();
$Log("Final Decision: " + result.Decision);
Next Steps¶
- Basic Quote Calculation - Premium calculation basics
- Underwriter Functions - Function reference