Credit decision display with explainability
onShowCalculation() → Opens modal with DSCR formula breakdownonShowDataSources() → Displays data lineage and quality scoresonViewCreditReport() → Shows full Experian/Equifax reportsonExploreOptions() → Navigates to CM06 (Scenario Explorer)Credit assessment and decision endpoint
/api/v1/applications/{application_id}/credit-assessmentPOST /api/v1/applications/app_20251222_143023_usr123/credit-assessment Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... Content-Type: application/json { "requested_amount": 150000, "requested_term_months": 36, "loan_purpose": "expansion", "run_soft_check": true // Doesn't affect credit score }
{
"request_id": "req_cm05_20251222_143545",
"status": "success",
"decision": {
"outcome": "approved", // "approved", "declined", "refer"
"max_loan_amount": 250000,
"min_loan_amount": 5000,
"recommended_amount": 150000,
"interest_rate_apr": 0.045,
"rate_type": "fixed",
"confidence_score": 0.95
},
"financial_metrics": {
"dscr": 2.27,
"revenue_growth_score": 92,
"profitability_score": 90,
"credit_profile_score": 95,
"cashflow_score": 88,
"overall_health_score": 85
},
"credit_bureau_results": {
"experian": {
"score": 780,
"max_score": 999,
"grade": "excellent",
"payment_history": "100% on-time",
"credit_utilization": 0.12,
"adverse_records": 0
},
"equifax": {
"score": 775,
"max_score": 999,
"grade": "excellent"
}
},
"affordability": {
"monthly_payment": 4520,
"disposable_income": 6320,
"affordability_ratio": 0.71,
"cashflow_buffer": 1800
},
"approval_factors": [
"Strong financials: 34% operating margin, growing revenue",
"Excellent DSCR of 2.27× (exceeds 1.25× minimum)",
"Outstanding credit scores (780/999, 775/999)",
"Healthy cashflow buffer (£1,800/month remaining)"
],
"risk_assessment": {
"risk_grade": "Low",
"probability_of_default": 0.021,
"loss_given_default": 0.45,
"expected_loss": 0.0095
},
"processing_time_ms": 4230,
"timestamp": "2025-12-22T14:35:45Z"
}
Gather all financial data from previous screens (CM02 data aggregation results).
Pull credit reports from Experian and Equifax for company and directors.
Calculate Debt Service Coverage Ratio to assess repayment capacity.
Verify customer can comfortably afford monthly loan payments.
Machine learning model calculates probability of default and risk grade.
Apply lending policy rules to determine eligibility and terms.
Determine interest rate, max loan amount, and recommended terms.
Total Processing Time: 3-5 seconds (bureau calls dominate processing time)
Credit assessment AI engine and policy rules
// Credit Assessor AI Engine async function assessCredit(applicationId) { // 1. Gather all input data const financial = await getFinancialData(applicationId); const creditBureau = await queryCreditBureaus(applicationId); const identity = await getIdentityData(applicationId); // 2. Calculate financial ratios const ratios = calculateFinancialRatios(financial); // - DSCR, profit margin, revenue growth, current ratio // - ROA, ROE, debt-to-equity, interest coverage // 3. Normalize and feature engineer const features = engineerFeatures({ ...ratios, credit_score: creditBureau.experian.score, years_trading: calculateYearsTrading(identity.company_incorporation), industry_code: getIndustryCode(financial.sic_code), loan_to_revenue_ratio: requestedAmount / financial.annual_revenue }); // 4. Run ML model prediction const mlPrediction = await creditModel.predict(features); // Returns: { pd: 0.021, risk_grade: 'Low', confidence: 0.95 } // 5. Apply policy rules (hard constraints) const policyCheck = applyPolicyRules({ dscr: ratios.dscr, credit_score: creditBureau.experian.score, adverse_records: creditBureau.adverse_count, years_trading: identity.years_trading, profit_margin: ratios.net_profit_margin }); // 6. Make final decision if (!policyCheck.passed) { return { outcome: 'declined', reasons: policyCheck.failures }; } if (mlPrediction.risk_grade === 'High') { return { outcome: 'refer', reason: 'Manual review required' }; } // 7. Calculate max loan amount and pricing const maxAmount = calculateMaxLoanAmount(ratios.dscr, financial.revenue); const apr = calculateAPR(mlPrediction.risk_grade, creditBureau.score); return { outcome: 'approved', max_amount: maxAmount, interest_rate: apr, risk_assessment: mlPrediction, factors: generateApprovalFactors(ratios, creditBureau) }; }
// Olivia's Café Example Operating Income (EBIT): Revenue: £450,000 - Operating Costs: £312,300 - Depreciation: £10,000 = EBIT: £127,700 Plus: Add back depreciation (non-cash): +£27,300 = Operating Income for DSCR: £155,000/year Existing Debt Payments: Equipment loan: £800/month × 12 = £9,600/year Overdraft interest: £100/month × 12 = £1,200/year = Total existing: £10,800/year New Loan Payment: £150K @ 4.5% over 36 months = £4,520/month = Annual payment: £54,240/year (Principal: £50K + Interest: £4,240) Total Debt Service: Existing + New = £10,800 + £54,240 = £65,040/year DSCR Calculation: £155,000 ÷ £65,040 = 2.38× // After adjustments for conservative estimates: Final DSCR: 2.27× ✓ (Exceeds 1.25× minimum)
Credit bureau integration and decision orchestration
async function queryCreditBureaus(companyNumber, directorDOB) { // Execute both API calls in parallel const [experianResult, equifaxResult] = await Promise.allSettled([ queryExperian(companyNumber, directorDOB), queryEquifax(companyNumber, directorDOB) ]); // Handle Experian response const experian = experianResult.status === 'fulfilled' ? experianResult.value : null; // Handle Equifax response const equifax = equifaxResult.status === 'fulfilled' ? equifaxResult.value : null; // If both failed, throw error if (!experian && !equifax) { throw new Error('All credit bureaus unavailable'); } // Return combined results return { experian: experian || { score: null, error: 'unavailable' }, equifax: equifax || { score: null, error: 'unavailable' }, primary_score: experian?.score || equifax?.score }; }
credit_assessment:{application_id}Credit bureau APIs
POST /businessinformation/reportPOST /businessinformation/report Authorization: Bearer {token} Content-Type: application/json { "companyNumber": "12345678", "checkType": "soft", "reportType": "detailed" } // Response: 780/999, Excellent grade
GET /commercial/credit-reportGET /commercial/credit-report ?companyNumber=12345678 &includeScore=true X-API-Key: {api_key} // Response: 775/999, Excellent grade
Credit assessment results and audit trail
CREATE TABLE credit_assessments ( assessment_id VARCHAR(50) PRIMARY KEY, application_id VARCHAR(50) REFERENCES applications, -- Decision outcome VARCHAR(20), -- 'approved', 'declined', 'refer' max_loan_amount DECIMAL(12,2), interest_rate_apr DECIMAL(5,4), confidence_score DECIMAL(3,2), -- Financial Metrics dscr DECIMAL(4,2), profit_margin DECIMAL(5,4), revenue_growth DECIMAL(5,4), overall_health_score INTEGER, -- Credit Bureau Results experian_score INTEGER, equifax_score INTEGER, credit_grade VARCHAR(20), adverse_records INTEGER, -- Risk Assessment risk_grade VARCHAR(20), probability_default DECIMAL(5,4), loss_given_default DECIMAL(5,4), expected_loss DECIMAL(5,4), -- Metadata ml_model_version VARCHAR(20), processing_time_ms INTEGER, created_at TIMESTAMP ); CREATE INDEX idx_app_id ON credit_assessments(application_id); CREATE INDEX idx_outcome ON credit_assessments(outcome);
UPDATE applications SET status = 'credit_assessed', credit_decision = 'approved', max_approved_amount = 250000, recommended_amount = 150000, interest_rate_apr = 0.045, risk_grade = 'Low', dscr = 2.27, credit_assessed_at = '2025-12-22 14:35:45', updated_at = '2025-12-22 14:35:45' WHERE application_id = 'app_20251222_143023_usr123';
{
"log_id": "log_cm05_20251222_143545",
"event_type": "credit_decision_made",
"screen": "CM05",
"user_id": "usr_olivia_thompson",
"application_id": "app_20251222_143023_usr123",
"timestamp": "2025-12-22T14:35:45Z",
"details": {
"decision": "approved",
"max_amount": 250000,
"apr": 0.045,
"dscr": 2.27,
"experian_score": 780,
"risk_grade": "Low",
"ml_model_version": "v2.4.1",
"confidence": 0.95,
"processing_time_ms": 4230
}
}
Debt service coverage ratio below minimum threshold
Both bureaus return scores below policy threshold
CCJs, defaults, or bankruptcies found in bureau report
Company incorporated less than 2 years ago
Both Experian and Equifax fail to respond within 5 seconds
ML model confidence <80% or medium-high risk grade
Business showing losses in latest financial year
Machine learning endpoint unavailable or returns error