Skip to content

Servicing Result Schema

The servicing result schema represents the complete output of a servicing calculation, including borrowing capacity, validation checks, rate breakdowns, and financial projections.

When you call the compute servicing endpoint, you receive a comprehensive analysis of whether a lender can service a loan and what the maximum borrowing capacity is.

interface ServicingResult {
// Core Results
lender_name: string;
does_service: boolean;
fail_service_reason: string | null;
max_borrowing_capacity: number;
net_monthly_surplus: number;
debt_to_income_ratio: number;
has_rate_override: boolean;
// Validation & Warnings
validations: Validation[];
warnings: Warning[];
// Rate & Product Information
per_loan_rate_breakdown: LoanRateBreakdown[];
// Projections
ytd_results: YearToDateResult[][];
// Lender-Specific Data
lender_specific_display_items?: LenderDisplayItem[];
lender_specific_results?: Record<string, any>;
// Detailed Breakdown (for advanced use)
interim_values?: InterimValues;
}
Primary Results
FieldTypeDescription
lender_namestringName of the lender (e.g., 'redzed', 'cba', 'westpac')
does_servicebooleanWhether this lender can service the proposed loan
fail_service_reasonstring | nullReason for service failure if does_service is false, otherwise null
max_borrowing_capacitynumberMaximum loan amount the lender will approve (AUD)
net_monthly_surplusnumberMonthly cashflow surplus after all commitments
debt_to_income_rationumberDTI ratio (total debt / annual income)
has_rate_overridebooleanWhether custom rate overrides were applied to this calculation

Example:

{
"lender_name": "redzed",
"does_service": true,
"fail_service_reason": null,
"max_borrowing_capacity": 2094569,
"net_monthly_surplus": 13916.81,
"debt_to_income_ratio": 2.32,
"has_rate_override": false
}
Validations

Array of validation checks performed by the lender’s servicing calculator.

FieldTypeDescription
typestringValidation type identifier (e.g., 'SIMPLE_BONUS_INCOME_WARNING')
isValidbooleanWhether the check passed
messagestringDetailed description of the validation result (may include markdown)
softWarningbooleanIf true, this is a warning that doesn’t prevent approval
allowServiceabilitybooleanWhether this validation allows the loan to proceed even if isValid is false

Example:

{
"validations": [
{
"type": "SIMPLE_BONUS_INCOME_WARNING",
"isValid": false,
"softWarning": true,
"allowServiceability": true,
"message": "**Simple Bonus Method Detected**: Please note that RedZed has a policy that bonus income will only be acceptable when the most recent two financial years are provided in servicing. Quickli is treating your bonus income as if it's already aligned with this policy."
},
{
"type": "REQUIRES_COMMITMENTS_MONTHLY_REPAYMENT",
"allowServiceability": true,
"isValid": false,
"message": "RedZed will use the inputted monthly repayment to include your commitments in the assessment (except for Credit Card, Margin and Overdraft). Quickli has detected that some of your commitments has $0 repayment, and hence applied $0 for that commitment to align with RedZed. Please ensure you enter the correct repayment amount, as this can have a significant impact on your application."
}
]
}

Understanding Validation Results:

  • isValid: false + allowServiceability: true = Warning only, loan can still proceed
  • isValid: false + allowServiceability: false = Hard stop, loan cannot proceed
  • softWarning: true = Informational notice for broker awareness
  • Messages may contain markdown formatting (e.g., **bold text**)

Common validation types:

  • Income verification requirements (SIMPLE_BONUS_INCOME_WARNING)
  • Commitment assessment policies (REQUIRES_COMMITMENTS_MONTHLY_REPAYMENT)
  • Minimum income thresholds
  • Maximum LVR limits
  • Debt service coverage ratios
  • Living expense minimums (HEM benchmark)
  • Property type restrictions
  • Employment type requirements
Warnings

Array of warning objects that don’t prevent loan approval but require attention. Warnings provide important context about policy interpretations, calculation methods, or potential risks.

FieldTypeDescription
_idstringUnique identifier for this warning type
messagestringDetailed warning message (may contain markdown/newlines)
warningLevelstringSeverity level (e.g., 'warning', 'info')
logicToTriggerWarningbooleanWhether the condition for this warning is currently met
orderPrioritystringDisplay priority ('high', 'medium', 'low')
shouldMakeRowAmberbooleanWhether this warning should highlight the result row
outOfScopeIfTriggeredbooleanWhether triggering makes the scenario out of scope
outOfScopeHeaderstringHeader text if out of scope
internalTagstringInternal classification tag

Example:

{
"warnings": [
{
"_id": "67ff4f7be2c3546ef71e4509",
"logicToTriggerWarning": true,
"orderPriority": "medium",
"warningLevel": "warning",
"message": "The HECS repayment used for RedZed is not based on their calculator, but on the ATO tables and can risk being open to interpretation or change without notice by the lender.\n\nThis is straightforward when there's only PAYG income, but less straightforward when there's other types of income, especially rental income/negative gearing.\n\nView HECS Policy below.",
"shouldMakeRowAmber": false,
"outOfScopeIfTriggered": false,
"outOfScopeHeader": "",
"internalTag": "GENERIC_HECS_CALCULATION"
}
]
}

Common warning scenarios:

  • HECS calculation methodology differences
  • Income verification requirements
  • Documentation needed for specific income types
  • Policy interpretation notes
  • Rate review periods
  • Future payment changes (IO to P&I conversion)
  • Lender-specific calculation approaches

How to handle warnings:

  • Review all warnings with logicToTriggerWarning: true
  • Pay special attention to warnings with orderPriority: 'high'
  • Ensure clients understand policy differences noted in warning messages
  • Check if outOfScopeIfTriggered: true indicates the scenario may not be suitable
Per-Loan Rate Breakdown

Detailed interest rate and product information for each proposed loan.

FieldTypeDescription
product_namestringName of the lender’s product (e.g., 'SE Prime')
svrnumberStandard Variable Rate (%) before discounts
discountnumberTotal discount applied to the SVR (%)
productFeesFee[]Array of product fees (see Product Fees Schema)
ongoingFeenumberTotal ongoing monthly fees
setupFeenumberTotal one-time setup fees

Example:

{
"per_loan_rate_breakdown": [
{
"product_name": "SE Prime",
"svr": 6.75,
"discount": 0.36,
"productFees": [
{
"name": "Settlement Fee",
"amount": 500,
"frequency": "once",
"payablePer": "split",
"payAt": "end",
"isPromotional": false
},
{
"name": "Account Management Fee",
"amount": 25,
"frequency": "monthly",
"description": "Per loan split",
"payablePer": "split",
"payAt": "start",
"isPromotional": false
}
// ... more fees (see Product Fees documentation)
],
"ongoingFee": 0,
"setupFee": 0
},
{
"product_name": "SE Prime",
"svr": 6.75,
"discount": 0.36,
"productFees": [/* ... */],
"ongoingFee": 0,
"setupFee": 0
}
]
}

Calculating the effective rate:

const effectiveRate = svr - discount;
// Example: 6.75% - 0.36% = 6.39%

Note: The productFees array can be extensive (10+ fees per product). See the Product Fees Schema for complete fee structure documentation.

Rate factors included in discount:

  • LVR-based discounts/premiums
  • Package/relationship discounts
  • Owner-occupied vs investment adjustments
  • Principal & Interest vs Interest-only adjustments
  • Loan amount tier discounts
Year-to-Date Results

Financial projections showing cashflow and loan balances over time.

FieldTypeDescription
yearnumberYear number (0 = current, 1 = year 1, etc.)
total_incomenumberTotal annual income
total_expensesnumberTotal annual expenses
total_loan_repaymentsnumberTotal annual loan repayments
remaining_balancenumberLoan balance at end of year
surplusnumberAnnual cashflow surplus

Example:

{
"ytd_results": [
{
"year": 0,
"total_income": 120000,
"total_expenses": 42000,
"total_loan_repayments": 48000,
"remaining_balance": 680000,
"surplus": 30000
},
{
"year": 1,
"total_income": 120000,
"total_expenses": 43260,
"total_loan_repayments": 48000,
"remaining_balance": 670500,
"surplus": 28740
}
]
}

Use cases:

  • Understanding long-term affordability
  • Planning for payment increases (e.g., IO to P&I conversion)
  • Stress testing scenarios
  • Comparing different loan structures

Note: ytd_results may be an empty array or array of empty arrays depending on lender and calculation type.

Lender-Specific Display Items

Additional metrics and calculations specific to each lender. These values provide insight into how the lender assesses the application.

FieldTypeDescription
sectionstringWhere this item should be displayed ('results' or 'interim')
namestringDisplay name of the metric
valuenumberCalculated value
unitsstringUnit type ('ratio', 'dollar', 'percentage')

Example:

{
"lender_specific_display_items": [
{
"section": "results",
"name": "DSR",
"value": 2.45,
"units": "ratio"
},
{
"section": "results",
"name": "DTI",
"value": 2.32,
"units": "ratio"
},
{
"section": "interim",
"name": "Personal Income",
"value": 24084,
"units": "dollar"
},
{
"section": "interim",
"name": "Rental Income",
"value": 8840,
"units": "dollar"
},
{
"section": "interim",
"name": "Total Monthly Net Income",
"value": 32924,
"units": "dollar"
},
{
"section": "interim",
"name": "Living Expenses (Assessed)",
"value": 9361,
"units": "dollar"
},
{
"section": "interim",
"name": "Available Income",
"value": 23563,
"units": "dollar"
},
{
"section": "interim",
"name": "Total Monthly Commitments (Actual)",
"value": 7969,
"units": "dollar"
},
{
"section": "interim",
"name": "Total Monthly Commitments (Assessed)",
"value": 9646,
"units": "dollar"
}
]
}

Common lender-specific metrics:

  • DSR (Debt Service Ratio): Total debt repayments / total income
  • DTI (Debt to Income): Total debt / annual income
  • Income breakdowns: Personal, rental, total net income
  • Expense assessments: Actual vs assessed living expenses
  • Commitment calculations: Actual vs assessed monthly commitments
  • Available Income: Income remaining after expenses

Note: Different lenders provide different metrics. This field may not be present for all lenders.

Interim Values (Advanced)

Detailed breakdown of all calculations performed during servicing assessment. Useful for debugging, auditing, or understanding exactly how the lender assessed the application.

Structure:

interface InterimValues {
net_monthly_surplus: {
eligible_income: number;
comparable_expenses: number;
non_comparable_expenses: number;
proposed_assessed_repayments: number;
existing_assessed_repayments: number;
existing_liability_repayments: number;
};
households: {
summaries: HouseholdSummary[];
assessed_expenses: number;
};
income: {
summaries: IncomeSummary[];
total_income: number;
};
rental_income: RentalIncomeSummary[];
liabilities: {
repayments: number[];
total_repayments: number;
};
existing_home_loans: HomeLoanDetails;
proposed_home_loans: HomeLoanDetails;
remarks: PolicyRemarks;
}

Key sections:

  1. net_monthly_surplus: Components of the surplus calculation
  2. households: HEM benchmarks and assessed living expenses per household
  3. income: Detailed income breakdown per applicant (taxable salary, rental, bonuses, tax offsets, HECS)
  4. rental_income: Rental yield caps and shading applied per property
  5. liabilities: Assessment of existing debts and commitments
  6. existing_home_loans: Existing loan details and repayment calculations
  7. proposed_home_loans: Proposed loan details, actual rates, and assessment rates
  8. remarks: Family tax benefit eligibility and other policy-specific notes

When to use interim_values:

  • Debugging why a calculation resulted in a specific value
  • Understanding how different income types were assessed
  • Auditing rental income shading or HECS calculations
  • Comparing lender-specific policy implementations
  • Building detailed reports for clients

Example access:

const applicant1Income = result.interim_values.income.summaries[0];
console.log('Taxable salary:', applicant1Income.taxable_salary);
console.log('Eligible income:', applicant1Income.eligible);
console.log('HECS repayment:', applicant1Income.hecs_assessed_repayment);
const household1 = result.interim_values.households.summaries[0];
console.log('HEM benchmark:', household1.hem_benchmark);
console.log('Actual expenses:', household1.actual_expenses);

Note: This field contains extensive calculation details and may be overwhelming for basic use cases. Most developers only need the top-level results fields.

Below is a real response from the RedZed lender with lenderName: "redzed" and addToRates: 0.5:

{
"data": {
"lender_name": "redzed",
"does_service": true,
"fail_service_reason": null,
"max_borrowing_capacity": 2094569,
"net_monthly_surplus": 13916.81,
"debt_to_income_ratio": 2.32,
"has_rate_override": false,
"validations": [
{
"type": "SIMPLE_BONUS_INCOME_WARNING",
"isValid": false,
"softWarning": true,
"allowServiceability": true,
"message": "**Simple Bonus Method Detected**: Please note that RedZed has a policy that bonus income will only be acceptable when the most recent two financial years are provided in servicing. Quickli is treating your bonus income as if it's already aligned with this policy."
},
{
"type": "REQUIRES_COMMITMENTS_MONTHLY_REPAYMENT",
"allowServiceability": true,
"isValid": false,
"message": "RedZed will use the inputted monthly repayment to include your commitments in the assessment (except for Credit Card, Margin and Overdraft). Quickli has detected that some of your commitments has $0 repayment, and hence applied $0 for that commitment to align with RedZed. Please ensure you enter the correct repayment amount, as this can have a significant impact on your application."
}
],
"warnings": [
{
"_id": "67ff4f7be2c3546ef71e4509",
"logicToTriggerWarning": true,
"orderPriority": "medium",
"warningLevel": "warning",
"message": "The HECS repayment used for RedZed is not based on their calculator, but on the ATO tables and can risk being open to interpretation or change without notice by the lender.\n\nThis is straightforward when there's only PAYG income, but less straightforward when there's other types of income, especially rental income/negative gearing.\n\nView HECS Policy below.",
"shouldMakeRowAmber": false,
"outOfScopeIfTriggered": false,
"outOfScopeHeader": "",
"internalTag": "GENERIC_HECS_CALCULATION"
}
],
"per_loan_rate_breakdown": [
{
"product_name": "SE Prime",
"svr": 6.75,
"discount": 0.36,
"productFees": [
{
"name": "Settlement Fee",
"amount": 500,
"frequency": "once",
"payablePer": "split",
"payAt": "end",
"isPromotional": false
},
{
"name": "Account Management Fee",
"amount": 25,
"frequency": "monthly",
"description": "Per loan split",
"payablePer": "split",
"payAt": "start",
"isPromotional": false
},
{
"name": "Establishment Fee",
"amount": 399,
"frequency": "once",
"description": "Payable at settlement & includes one standard security appraisal of a property ≤ $2M.",
"payablePer": "application",
"payAt": "start",
"isPromotional": false
}
// ... additional fees (see Product Fees documentation)
],
"ongoingFee": 0,
"setupFee": 0
}
],
"ytd_results": [[], [], []],
"lender_specific_display_items": [
{
"section": "results",
"name": "DSR",
"value": 2.45,
"units": "ratio"
},
{
"section": "results",
"name": "DTI",
"value": 2.32,
"units": "ratio"
},
{
"section": "interim",
"name": "Personal Income",
"value": 24084,
"units": "dollar"
},
{
"section": "interim",
"name": "Total Monthly Net Income",
"value": 32924,
"units": "dollar"
}
],
"lender_specific_results": {
"debt_service_ratio": 2.442751474621408
}
// interim_values omitted for brevity (see Interim Values section above)
},
"meta": {
"timestamp": "2025-11-06T03:47:17.053Z"
}
}

The loan passes all mandatory validation checks:

  • ✅ Income is sufficient
  • ✅ LVR is within limits
  • ✅ Debt service ratios are acceptable
  • ✅ Living expenses meet minimum benchmarks
  • ✅ No deal-breaking policy restrictions

Action: Proceed with the loan application at the calculated rate.

The loan fails one or more mandatory validation checks. This occurs when:

  • A validation has isValid: false AND allowServiceability: false
  • Critical policy restrictions prevent loan approval

Common failure scenarios:

  • ❌ Insufficient income for requested loan amount
  • ❌ LVR too high
  • ❌ Debt service coverage inadequate
  • ❌ Hard policy restriction triggered

Action: Review validations array to find checks where isValid: false and allowServiceability: false, then adjust the scenario accordingly.

Important: Not all isValid: false validations prevent serviceability. Check the allowServiceability field to determine if it’s a hard stop or just a warning.

Represents the maximum loan amount this lender will approve given:

  • Applicant’s income
  • Existing liabilities
  • Living expenses
  • Property details
  • Lender’s assessment rate

If max_borrowing_capacity < requested loan_amount, the loan won’t service.

Remaining monthly cashflow after:

  • All loan repayments (at assessment rate)
  • Existing liabilities
  • Living expenses
  • Other commitments

Most lenders require a minimum surplus (typically $0-$500) for loan approval.

if (result.does_service) {
const effectiveRate = result.per_loan_rate_breakdown[0].svr - result.per_loan_rate_breakdown[0].discount;
console.log(`✓ Loan services with ${result.lender_name}`);
console.log(`Effective rate: ${effectiveRate.toFixed(2)}%`);
console.log(`Max capacity: $${result.max_borrowing_capacity.toLocaleString()}`);
} else {
console.log('✗ Loan does not service');
console.log(`Reason: ${result.fail_service_reason}`);
// Show hard stops (validation failures that prevent serviceability)
const hardStops = result.validations.filter(v => !v.isValid && !v.allowServiceability);
if (hardStops.length > 0) {
console.log('\nHard stops:');
hardStops.forEach(v => console.log(`- ${v.type}: ${v.message}`));
}
}
// Always check for warnings, even if loan services
const activeWarnings = result.validations.filter(v => !v.isValid && v.allowServiceability);
if (activeWarnings.length > 0) {
console.log('\n⚠️ Warnings (loan can still proceed):');
activeWarnings.forEach(v => console.log(`- ${v.type}: ${v.message}`));
}
console.log(`Maximum borrowing: $${result.max_borrowing_capacity.toLocaleString()}`);
if (result.max_borrowing_capacity < requestedAmount) {
const shortfall = requestedAmount - result.max_borrowing_capacity;
console.log(`Shortfall: $${shortfall.toLocaleString()}`);
console.log('Consider: increasing income, reducing liabilities, or adding a co-applicant');
}
result.per_loan_rate_breakdown.forEach((loan, index) => {
console.log(`Loan ${index + 1} (${loan.product_name}):`);
console.log(`- SVR: ${loan.svr}%`);
console.log(`- Discount: ${loan.discount}%`);
console.log(`- Effective rate: ${(loan.svr - loan.discount).toFixed(2)}%`);
// Show key fees
const monthlyFees = loan.productFees.filter(f => f.frequency === 'monthly');
const onceFees = loan.productFees.filter(f => f.frequency === 'once');
if (monthlyFees.length > 0) {
console.log('Monthly fees:');
monthlyFees.forEach(f => console.log(` - ${f.name}: $${f.amount}`));
}
if (onceFees.length > 0) {
console.log('One-time fees:');
onceFees.forEach(f => console.log(` - ${f.name}: $${f.amount}`));
}
});
// Note: ytd_results may be an empty array or array of empty arrays
if (result.ytd_results && result.ytd_results.length > 0 && result.ytd_results[0].length > 0) {
result.ytd_results[0].forEach((year, index) => {
console.log(`Year ${index}:`);
console.log(`- Income: $${year.total_income.toLocaleString()}`);
console.log(`- Expenses: $${year.total_expenses.toLocaleString()}`);
console.log(`- Repayments: $${year.total_loan_repayments.toLocaleString()}`);
console.log(`- Surplus: $${year.surplus.toLocaleString()}`);
});
} else {
console.log('YTD projections not available for this lender');
}
// Display lender-specific calculations (e.g., DSR, DTI)
const resultMetrics = result.lender_specific_display_items?.filter(item => item.section === 'results') || [];
const interimMetrics = result.lender_specific_display_items?.filter(item => item.section === 'interim') || [];
console.log('Key Metrics:');
resultMetrics.forEach(metric => {
if (metric.units === 'ratio') {
console.log(`- ${metric.name}: ${metric.value.toFixed(2)}`);
} else if (metric.units === 'dollar') {
console.log(`- ${metric.name}: $${metric.value.toLocaleString()}`);
}
});
// Access detailed income/expense breakdown if needed
if (interimMetrics.length > 0) {
console.log('\nDetailed Breakdown:');
interimMetrics.forEach(metric => {
console.log(`- ${metric.name}: $${metric.value.toLocaleString()}`);
});
}
{
"does_service": true,
"fail_service_reason": null,
"max_borrowing_capacity": 2094569,
"net_monthly_surplus": 13916.81,
"validations": [
{
"type": "SIMPLE_BONUS_INCOME_WARNING",
"isValid": false,
"allowServiceability": true,
"softWarning": true
}
]
}

Interpretation: Strong application with significant buffer ($13,916 surplus). Loan amount well within capacity ($2M+). Note that isValid: false doesn’t prevent approval when allowServiceability: true.

{
"does_service": true,
"fail_service_reason": null,
"max_borrowing_capacity": 650000,
"net_monthly_surplus": 150,
"validations": [
{
"type": "MINIMUM_SURPLUS_CHECK",
"isValid": true,
"allowServiceability": true
}
]
}

Interpretation: Loan just scrapes through with minimal surplus ($150/month). Small changes in income or expenses could tip it over. Consider stress testing with addToRates parameter.

{
"does_service": false,
"fail_service_reason": "Insufficient surplus to meet minimum requirements",
"max_borrowing_capacity": 580000,
"net_monthly_surplus": -450,
"validations": [
{
"type": "MINIMUM_SURPLUS_CHECK",
"isValid": false,
"allowServiceability": false,
"message": "Monthly surplus of -$450 is below minimum requirement of $0"
}
]
}

Interpretation: Loan amount ($650k requested) exceeds capacity ($580k). Hard stop with allowServiceability: false. Need to reduce loan by $70k, increase income, or reduce existing commitments.


Last updated: 2025-11-03