Revenue Recovery Score™ Methodology
The complete technical specification: exact piecewise formulas, weighted scoring categories, industry normalization factors, benchmark ranges, and implementation pseudocode.
This document is the authoritative reference for implementing the Revenue Recovery Score™ in software. Every formula, threshold, and weight is defined with sufficient precision for engineering teams to build against.
Scoring Architecture Overview
Two-Layer Scoring Model
Exact Formulas — All 5 Sub-Factors
Precise piecewise functions with variable definitions and scoring rubrics.
C — Missed Call Recovery
Weight: Variable (0.10-0.35)
C = 100 × (1 − missedCallRate) × afterHoursPenalty
missedCallRateUnanswered calls ÷ total inbound callsafterHoursPenalty1.0 if business-hours coverage ≥ 95%; 0.85 if 70-94%; 0.65 if < 70%R — Response Time Velocity
Weight: Variable (0.20-0.30)
R = 100 × e^(−k × avgResponseMinutes)
avgResponseMinutesWeighted average first-response time across voice (40%), web (30%), SMS (20%), email (10%)kDecay constant: 0.0693 (half-life = 10 minutes)Q — Lead Qualification Rate
Weight: Variable (0.10-0.30)
Q = 100 × (qualifiedLeads ÷ totalInquiries) × qualificationDepthFactor
qualifiedLeadsLeads that pass a documented qualification processtotalInquiriesAll inbound inquiries across all channelsqualificationDepthFactor1.0 if multi-criteria scoring used; 0.75 if single-criterion; 0.50 if no formal processF — Follow-Up Completion
Weight: Variable (0.10-0.25)
F = 100 × (leadsWithFollowUp ÷ totalUnconvertedLeads) × channelMultiplier
leadsWithFollowUpUnconverted leads receiving ≥ 2 contact attempts within 48 hourstotalUnconvertedLeadsAll leads that did not convert on first contactchannelMultiplier1.0 if ≥ 3 channels used; 0.80 if 2 channels; 0.60 if 1 channel; 0.40 if no follow-up systemS — Appointment Conversion
Weight: Variable (0.10-0.25)
S = 100 × (bookedAppointments ÷ qualifiedLeads) × (1 − noShowRate) × bookingEaseFactor
bookedAppointmentsConfirmed appointments from qualified leadsqualifiedLeadsLeads that passed qualificationnoShowRateAppointments not attended without prior cancellationbookingEaseFactor1.0 if self-service online booking; 0.85 if mixed; 0.65 if phone/email only; 0.50 if no formal schedulingIndustry Normalization Factors
Different industries have different revenue levers. The weighting model adjusts accordingly.
Weight Matrix by Industry
The default weight set (C=0.30, R=0.25, Q=0.20, F=0.15, S=0.10) is the "general business" baseline. Industry-specific weights are applied based on the audited company's primary sector. All weight sets satisfy Σ = 1.0 and all w ∈ [0.10, 0.35].
| Industry | C (Call) | R (Response) | Q (Qualification) | F (Follow-Up) | S (Scheduling) | Rationale |
|---|---|---|---|---|---|---|
| Behavioral Health & Recovery | 0.35 | 0.20 | 0.20 | 0.15 | 0.10 | Call-driven admissions; phone answer rate is the dominant revenue lever. |
| Home Healthcare | 0.30 | 0.25 | 0.20 | 0.15 | 0.10 | Referral-heavy; response time to hospital discharges is critical. |
| Medical Practice | 0.25 | 0.20 | 0.15 | 0.15 | 0.25 | Scheduling efficiency dominates — no-shows directly destroy revenue. |
| Legal | 0.30 | 0.25 | 0.25 | 0.10 | 0.10 | High-value leads; qualification accuracy prevents wasted partner time. |
| HVAC / Plumbing / Electrical | 0.35 | 0.30 | 0.10 | 0.15 | 0.10 | Emergency-driven; call answer rate and response speed define revenue. |
| Roofing | 0.25 | 0.25 | 0.20 | 0.20 | 0.10 | Longer sales cycles; follow-up persistence closes deals. |
| Real Estate | 0.25 | 0.30 | 0.15 | 0.15 | 0.15 | Speed-to-lead dominant; 5-minute response window defines outcomes. |
| SaaS / Technology | 0.10 | 0.20 | 0.25 | 0.25 | 0.20 | Digital-first; qualification and nurture conversion matter most. |
| Insurance | 0.20 | 0.25 | 0.25 | 0.20 | 0.10 | Complex qualification required; wrong-fit leads waste underwriting time. |
| Financial Services | 0.15 | 0.20 | 0.30 | 0.20 | 0.15 | Regulatory qualification gates; accuracy trumps speed. |
| Multi-Location Enterprise | 0.25 | 0.20 | 0.15 | 0.15 | 0.10 | Standardized; remaining 15% allocated to location-variance penalty factor. |
Behavioral Health, Trades — phone is the primary revenue channel. C + R weights exceed 0.60 combined.
Legal, Financial Services, Insurance — wrong-fit leads are expensive. Q weight rises to 0.25-0.30.
Medical Practice, SaaS — conversion lives in the booking flow. S weight rises to 0.20-0.25.
Industry Benchmarks — Top Quartile
75th-percentile scores by industry, derived from aggregate audit data. Use these as reference targets.
| Industry | RRS | C | R | Q | F | S | Key Insight |
|---|---|---|---|---|---|---|---|
| Behavioral Health | 82 | 92 | 88 | 85 | 78 | 72 | Call-driven; high answer rates but scheduling friction from insurance verification. |
| Home Healthcare | 79 | 88 | 85 | 82 | 75 | 70 | Referral networks buffer leakage; response time to hospital discharges is the critical lever. |
| Medical Practice | 76 | 78 | 72 | 74 | 68 | 85 | Strong scheduling; weak on call answer and follow-up. |
| Legal | 74 | 85 | 72 | 80 | 62 | 71 | High-value leads but notoriously slow response. |
| HVAC / Plumbing / Electrical | 68 | 65 | 70 | 55 | 60 | 75 | Emergency calls drive urgency, but many shops under-index on phone coverage. |
| Roofing | 71 | 72 | 68 | 70 | 74 | 68 | Follow-up persistence wins; longer sales cycles reward nurture. |
| Real Estate | 73 | 70 | 62 | 68 | 65 | 78 | Speed-to-lead is the single biggest variable in agent performance. |
| SaaS | 80 | 45 | 75 | 88 | 85 | 82 | Phone is minor; digital qualification and nurture dominate. |
Worked Example — Mid-Market HVAC Company
A complete walkthrough of the Revenue Recovery Score™ calculation.
Raw Data (30-Day Period)
Step-by-Step Calculation
C — Call Answer Rate
52Answer rate = (840 − 168) ÷ 840 = 0.80 After-hours coverage = 0%, penalty = 0.65 C = 100 × 0.80 × 0.65 = 52.0
R — Response Time Velocity
44avgResponseMinutes = 12 k = 0.0693 R = 100 × e^(−0.0693 × 12) = 100 × e^(−0.8316) = 100 × 0.4353 = 43.5
Q — Lead Qualification Rate
25Qual rate = 320 ÷ 960 = 0.333 Single-criterion → depthFactor = 0.75 Q = 100 × 0.333 × 0.75 = 25.0
F — Follow-Up Completion
20Follow-up rate = 180 ÷ 720 = 0.25 2 channels → channelMult = 0.80 F = 100 × 0.25 × 0.80 = 20.0
S — Appointment Conversion
24Conversion rate = 160 ÷ 320 = 0.50 Show rate = 1 − (40 ÷ 160) = 0.75 Phone-only → bookingFactor = 0.65 S = 100 × 0.50 × 0.75 × 0.65 = 24.4
Revenue Recovery Score™ — HVAC Weights
Implementation Reference — TypeScript
Production-ready pseudocode for engineering teams. Complete, typed, and self-documenting.
Step 1: Collect Raw Metrics
function collectMetrics(companyId: string): RawMetrics {
return {
totalCalls: fetchPhoneSystemLogs(companyId, period).inbound,
missedCalls: fetchPhoneSystemLogs(companyId, period).missed,
afterHoursCalls: fetchPhoneSystemLogs(companyId, period).afterHours,
afterHoursAnswered:fetchPhoneSystemLogs(companyId, period).afterHoursAnswered,
webInquiries: fetchCRM(companyId, period).webFormSubmissions,
webResponses: fetchCRM(companyId, period).webFormResponses,
smsInquiries: fetchMessagingLogs(companyId, period).smsInbound,
smsResponses: fetchMessagingLogs(companyId, period).smsResponses,
emailInquiries: fetchCRM(companyId, period).emailInbound,
emailResponses: fetchCRM(companyId, period).emailResponses,
avgResponseTimeMs: fetchCRMTimestamps(companyId, period).avgFirstResponse,
qualifiedLeads: fetchCRM(companyId, period).qualifiedCount,
totalInquiries: fetchCRM(companyId, period).totalInquiries,
leadsWithFollowUp: fetchCRM(companyId, period).followedUpCount,
unconvertedLeads: fetchCRM(companyId, period).unconvertedCount,
bookedAppts: fetchScheduling(companyId, period).booked,
noShows: fetchScheduling(companyId, period).noShows,
channelsUsed: detectFollowUpChannels(companyId, period),
hasMultiCriteria: detectQualificationMethod(companyId),
hasSelfService: detectBookingMethod(companyId),
industry: fetchCompanyProfile(companyId).industry,
};
}Step 2: Calculate Sub-Factor Scores (0-100 each)
function scoreCallAnswer(m: RawMetrics): number {
const answerRate = (m.totalCalls - m.missedCalls) / m.totalCalls;
const afterHoursCoverage = m.afterHoursAnswered / m.afterHoursCalls;
const afterHoursPenalty = afterHoursCoverage >= 0.95 ? 1.0
: afterHoursCoverage >= 0.70 ? 0.85
: 0.65;
return clamp(100 * answerRate * afterHoursPenalty, 0, 100);
}
function scoreResponseTime(m: RawMetrics): number {
// Exponential decay: half-life = 10 minutes
const avgMinutes = m.avgResponseTimeMs / 60000;
const k = 0.0693; // ln(2) / 10
return clamp(100 * Math.exp(-k * avgMinutes), 0, 100);
}
function scoreQualification(m: RawMetrics): number {
const qualRate = m.qualifiedLeads / m.totalInquiries;
const depthFactor = m.hasMultiCriteria ? 1.0
: m.hasQualification ? 0.75
: 0.50;
return clamp(100 * qualRate * depthFactor, 0, 100);
}
function scoreFollowUp(m: RawMetrics): number {
const followUpRate = m.leadsWithFollowUp / m.unconvertedLeads;
const channelMult = m.channelsUsed >= 3 ? 1.0
: m.channelsUsed >= 2 ? 0.80
: m.channelsUsed >= 1 ? 0.60
: 0.40;
return clamp(100 * followUpRate * channelMult, 0, 100);
}
function scoreScheduling(m: RawMetrics): number {
const conversionRate = m.bookedAppts / m.qualifiedLeads;
const showRate = 1 - (m.noShows / m.bookedAppts);
const bookingFactor = m.hasSelfService ? 1.0
: m.hasMixedBooking ? 0.85
: m.hasPhoneBooking ? 0.65
: 0.50;
return clamp(100 * conversionRate * showRate * bookingFactor, 0, 100);
}Step 3: Apply Industry-Specific Weights
const INDUSTRY_WEIGHTS: Record<string, Weights> = {
"behavioral-health": { c: 0.35, r: 0.20, q: 0.20, f: 0.15, s: 0.10 },
"home-healthcare": { c: 0.30, r: 0.25, q: 0.20, f: 0.15, s: 0.10 },
"medical-practice": { c: 0.25, r: 0.20, q: 0.15, f: 0.15, s: 0.25 },
"legal": { c: 0.30, r: 0.25, q: 0.25, f: 0.10, s: 0.10 },
"hvac": { c: 0.35, r: 0.30, q: 0.10, f: 0.15, s: 0.10 },
"plumbing": { c: 0.35, r: 0.30, q: 0.10, f: 0.15, s: 0.10 },
"electrical": { c: 0.35, r: 0.30, q: 0.10, f: 0.15, s: 0.10 },
"roofing": { c: 0.25, r: 0.25, q: 0.20, f: 0.20, s: 0.10 },
"real-estate": { c: 0.25, r: 0.30, q: 0.15, f: 0.15, s: 0.15 },
"saas": { c: 0.10, r: 0.20, q: 0.25, f: 0.25, s: 0.20 },
"insurance": { c: 0.20, r: 0.25, q: 0.25, f: 0.20, s: 0.10 },
"financial-services":{ c: 0.15, r: 0.20, q: 0.30, f: 0.20, s: 0.15 },
"enterprise": { c: 0.25, r: 0.20, q: 0.15, f: 0.15, s: 0.10 },
};
const DEFAULT_WEIGHTS = { c: 0.30, r: 0.25, q: 0.20, f: 0.15, s: 0.10 };
function getWeights(industry: string): Weights {
return INDUSTRY_WEIGHTS[industry] || DEFAULT_WEIGHTS;
}Step 4: Compute Revenue Recovery Score™
interface RRSResult {
score: number; // 0-100 composite
tier: string; // "Leader" | "Strong" | "Moderate" | "At Risk" | "Critical"
subScores: SubScores; // Individual factor scores
weights: Weights; // Applied weights
industry: string; // Industry used for normalization
}
interface SubScores {
callAnswer: number; // C — Missed Call Recovery, 0-100
responseTime: number; // R — Response Time Velocity, 0-100
qualification: number; // Q — Lead Qualification Rate, 0-100
followUp: number; // F — Follow-Up Completion, 0-100
scheduling: number; // S — Appointment Conversion, 0-100
}
function computeRRS(companyId: string): RRSResult {
const m = collectMetrics(companyId);
const weights = getWeights(m.industry);
const subScores: SubScores = {
callAnswer: scoreCallAnswer(m),
responseTime: scoreResponseTime(m),
qualification: scoreQualification(m),
followUp: scoreFollowUp(m),
scheduling: scoreScheduling(m),
};
const score = clamp(
subScores.callAnswer * weights.c +
subScores.responseTime * weights.r +
subScores.qualification * weights.q +
subScores.followUp * weights.f +
subScores.scheduling * weights.s,
0, 100
);
return {
score: Math.round(score),
tier: classifyTier(score),
subScores,
weights,
industry: m.industry,
};
}
function classifyTier(score: number): string {
if (score >= 90) return "Revenue Recovery Leader";
if (score >= 75) return "Strong Performer";
if (score >= 50) return "Moderate Leakage";
if (score >= 25) return "At Risk";
return "Critical";
}
function clamp(value: number, min: number, max: number): number {
return Math.max(min, Math.min(max, value));
}Step 5: Multi-Location Aggregation
function computeMultiLocationRRS(locationIds: string[]): MultiLocationResult {
const results = locationIds.map(id => computeRRS(id));
return {
enterpriseScore: weightedAverage(results, "revenue"), // Revenue-weighted
locationScores: results,
best: results.reduce((a, b) => a.score > b.score ? a : b),
worst: results.reduce((a, b) => a.score < b.score ? a : b),
variance: calculateVariance(results),
atRiskLocations: results.filter(r => r.score < 50),
};
}Implementation Notes
Ready to See Your Revenue Recovery Score™?
This methodology powers every audit. Request yours and receive a complete executive assessment within 48 hours.
Generated by TELEGENT AI™
The Business Impact Platform™
Workforce Intelligence™ For Businesses That Want More Impact.
© 2026 TELEGENT AI™
All Rights Reserved.
Confidential and Proprietary. Prepared exclusively for the recipient organization. This report contains proprietary TELEGENT AI™ methodologies, scoring models, and business intelligence frameworks. No part of this document may be reproduced, distributed, or transmitted without the prior written permission of TELEGENT AI™.
