Intent Spec — finance.apply_home_loan
FULL ID: finance.apply_home_loan
VERSION: v1.0.0
STATUS: draft
LAST UPDATED: 2026-05-13
DOMAIN: finance
PRIMARY AGENT: FinanceAgent
TTBS WEIGHTS: time=0.15 taste=0.10 budget=0.40 safety=0.35
User applies for a secured home loan (purchase, construction, plot, balance transfer, top-up, or loan-against-property). Covers eligibility check, property document collection, legal + technical valuation orchestration, KYC, sanction, disbursement (tranche-based for construction), and registration. Distinct from personal / vehicle loans.
Partner exemplars: BankBazaar, PaisaBazaar, MagicBricks Home Loan, HDFC Ltd (Bank), SBI Home Loan, LIC Housing Finance, ICICI Bank Home Loan, Axis Bank Home Loan, Tata Capital Housing, PNB Housing Finance, Bajaj Housing Finance.
SECTION 1 — INTENT IDENTITY
User wants a secured housing finance facility. Distinct from:
finance.apply_personal_loan— unsecuredfinance.apply_credit_card— revolving credit- Vehicle loans — v1.1+
- Loan against fixed deposits — v1.1+
- Reverse mortgage — v1.1+
- Loan against jewellery — v1.1+ gold loan
- Bridge loan — v1.1+
Single intent per application. Joint applications use co_applicants array.
SECTION 2 — NATURAL LANGUAGE COVERAGE
CLASSIFIES IN
- "Home loan ₹50 lakh, 20 years"
- "Best home loan interest rate for salaried"
- "Balance transfer my home loan to HDFC"
- "Home loan top up"
- "Plot purchase loan"
- "Home construction loan"
- "Loan against my flat"
- "Self-employed home loan options"
- "Joint home loan with my wife"
- "Pre-approved home loan eligibility"
CLASSIFIES OUT — BORDERLINE NO
- "Personal loan" →
finance.apply_personal_loan - "Credit card" →
finance.apply_credit_card - "Reverse mortgage" → v1.1+
- "Property to buy" →
marketplace.buy_used_caris for vehicles only; v1.1+ for real-estate listings - "EMI calculator" — non-transactional research
- "Foreclose home loan" → v1.1+
MULTI-INTENT TRIGGERS
- "Home loan + insurance" →
finance.apply_home_loan+finance.buy_term_insurance(loan-protection) - "Home loan + financial advisor" →
finance.apply_home_loan+finance.book_financial_advisor_session - "Home loan + tax consultation" →
finance.apply_home_loan+finance.book_tax_consultation(§24, §80C deductions)
SECTION 3 — INPUT (TOMO → PROVIDER)
{
"intent": "finance.apply_home_loan",
"request_id": "req_01J9Z...",
"user_locale": "en-IN",
"user_currency": "INR",
"user_location": { "lat": 17.4475, "lng": 78.3563, "city": "Hyderabad", "pincode": "500032" },
"loan_purpose": "purchase", // STRICT ENUM §6
"primary_applicant": {
"first_name": "Rakesh", "last_name": "Kumar",
"date_of_birth": "1985-04-18",
"gender": "male",
"pan_last4": "5678",
"mobile_e164": "+919876543210",
"marital_status": "married",
"employment": {
"type": "salaried_corporate", // STRICT ENUM §6
"industry": "information_technology", // STRICT ENUM §6
"designation": "Director of Engineering",
"years_at_current_employer": 5,
"total_work_experience_years": 14,
"net_monthly_income_inr": 280000,
"gross_annual_income_inr": 4000000,
"company_category": "listed_or_psu"
},
"obligations": {
"existing_emi_monthly_inr": 22000,
"credit_cards_outstanding_inr": 60000,
"consent_for_credit_bureau_pull": true,
"consent_for_aa_aggregator_pull": true
}
},
"co_applicants": [
{
"first_name": "Anita", "last_name": "Kumar",
"date_of_birth": "1988-09-12",
"relationship_to_primary": "spouse",
"pan_last4": "1234",
"employment_type": "salaried_corporate",
"net_monthly_income_inr": 180000
}
],
"property": {
"property_type": "ready_apartment", // STRICT ENUM §6
"occupancy_status": "self_occupied_post_disbursement", // STRICT ENUM §6
"city": "Hyderabad",
"pincode": "500032",
"state": "TS",
"agreement_value_inr": 8500000,
"expected_market_value_inr": 9000000,
"ready_for_possession": true,
"completion_certificate_available": true,
"rera_registration_number": "P02400001234",
"builder_or_seller_name": "ABC Developers Pvt Ltd",
"approved_project_by_lender": []
},
"loan_request": {
"amount_inr": 6500000,
"tenure_months": 240,
"rate_type_preference": "floating", // STRICT ENUM §6
"want_overdraft_facility": false,
"step_up_emi": false,
"first_emi_date_preference": "salary_date",
"want_balance_transfer": false,
"existing_loan_outstanding_inr": 0,
"existing_loan_lender": null
},
"ttbs_user_band": {
"time": "balanced",
"taste": "balanced",
"budget": "great",
"safety": "great"
},
"session_context": { "tomo_session_id": "ses_01J9Z...", "user_dna_hash": "dna_v3_a7c9..." }
}
| Field | Type | Constraint | Notes |
|---|---|---|---|
intent |
string | REQUIRED, STRICT ENUM | Always finance.apply_home_loan |
loan_purpose |
enum | REQUIRED, STRICT ENUM §6 | Drives valuation + tenure rules |
primary_applicant.pan_last4 |
string | REQUIRED, 4 digits | |
primary_applicant.employment.type |
enum | REQUIRED, STRICT ENUM §6 | Salaried / self-employed underwriting differ |
co_applicants |
array | REQUIRED, may be empty, max 3 | Income clubbed for eligibility |
property.property_type |
enum | REQUIRED, STRICT ENUM §6 | Drives LTV cap |
property.rera_registration_number |
string | REQUIRED nullable | Mandatory for under-construction; nullable for resale |
property.agreement_value_inr |
int | REQUIRED, INR_INTEGER, ≥0 | Drives LTV |
property.expected_market_value_inr |
int | REQUIRED, INR_INTEGER, ≥0 | Independent estimate |
loan_request.amount_inr |
int | REQUIRED, INR_INTEGER, ≥100000 | |
loan_request.tenure_months |
int | REQUIRED, 36-360 | Up to 30y |
loan_request.rate_type_preference |
enum | REQUIRED, STRICT ENUM §6 | fixed / floating / hybrid |
loan_request.want_balance_transfer |
bool | REQUIRED | When TRUE, existing_loan_* REQUIRED non-null |
Anti-fabrication preamble: APR must include all fees + bundled charges per RBI KFS Master Direction. LTV cap per RBI norms (up to ₹30L: 90%; ₹30-75L: 80%; >₹75L: 75%). No mandatory life-insurance bundle (RBI 2023). Floating-rate retail home loans no prepayment charge per RBI directive.
SECTION 4 — PROVIDER TOOLS
Tool 1: search_home_loan_offers
PURPOSE: Up to 10 offers from eligible lenders (soft-pull-based)
SLA: p50 ≤ 1200ms, p95 ≤ 4000ms, p99 ≤ 8000ms
RATE LIMIT: 45 req/min
IDEMPOTENCY: request_id; 10min cache
RETRY: 1 on 429, 2 on 5xx
Tool 2: initiate_application_and_valuation
PURPOSE: Full app + property doc upload + legal & technical valuation booking
SLA: p50 ≤ 3500ms, p95 ≤ 9000ms, p99 ≤ 18000ms
RATE LIMIT: 20 req/min
IDEMPOTENCY: request_id
RETRY: No retry
Tool 3: schedule_valuation_visits
PURPOSE: Book legal + technical valuation visits at property
SLA: p50 ≤ 1500ms, p95 ≤ 4000ms
RATE LIMIT: 30 req/min
IDEMPOTENCY: application_id
RETRY: 1 on 5xx
Tool 4: accept_sanction_and_disburse
PURPOSE: Sanction acceptance + first / tranche disbursement
SLA: p50 ≤ 3000ms, p95 ≤ 8000ms, p99 ≤ 20000ms
RATE LIMIT: 20 req/min
IDEMPOTENCY: application_id (single sanction) / tranche_id (multi-tranche)
RETRY: No retry
Tool 5: cancel_pre_disbursement
PURPOSE: Cancel application pre-disbursement
SLA: p50 ≤ 1500ms, p95 ≤ 4000ms
RATE LIMIT: 30 req/min
IDEMPOTENCY: application_id
RETRY: 1 on 5xx
SECTION 5 — RESPONSE SHAPE
HomeLoanOffer
HomeLoanOffer:
offer_id: { type: string, constraint: REQUIRED, opaque }
lender:
lender_id: { type: string, constraint: REQUIRED }
name: { type: string, constraint: REQUIRED }
lender_type: { type: enum, constraint: REQUIRED, STRICT ENUM §6 }
rbi_registration_number: { type: string, constraint: REQUIRED }
nhb_registration_number: { type: string, constraint: REQUIRED nullable, semantics: "Required for housing finance companies" }
ratings:
crisil_long_term: { type: string, constraint: REQUIRED nullable }
icra_long_term: { type: string, constraint: REQUIRED nullable }
care_long_term: { type: string, constraint: REQUIRED nullable }
is_pre_approved: { type: boolean, constraint: REQUIRED }
pa_offer_window_days: { type: int, constraint: REQUIRED, ≥0 }
loan_amount_offered_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
loan_amount_max_eligible_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
ltv_pct: { type: float, constraint: REQUIRED, 0-90 }
tenure_months: { type: int, constraint: REQUIRED, 36-360 }
rate_type: { type: enum, constraint: REQUIRED, STRICT ENUM §6 }
interest_rate_pct: { type: float, constraint: REQUIRED, 0-15 }
rate_benchmark:
type: enum
constraint: REQUIRED, STRICT ENUM §6
values: [eblr, mclr, base_rate_legacy, fixed_promised]
rate_spread_pct: { type: float, constraint: REQUIRED, -2 to 5, semantics: "Bps above/below benchmark" }
apr_pct: { type: float, constraint: REQUIRED, 0-20 }
emi_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
total_interest_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
total_repayment_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
fees:
processing_fee_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
processing_fee_pct: { type: float, constraint: REQUIRED, 0-2 }
gst_on_fees_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
legal_and_technical_valuation_fee_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
documentation_fee_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
cersai_charge_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
franking_charge_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
insurance_premium_bundled_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0, semantics: "0 unless user opts in" }
prepayment_terms:
full_prepayment_charge_pct: { type: float, constraint: REQUIRED, 0-3 }
part_prepayment_charge_pct: { type: float, constraint: REQUIRED, 0-3 }
part_prepayment_min_pct: { type: float, constraint: REQUIRED, 0-50 }
part_prepayment_max_per_year: { type: int, constraint: REQUIRED, ≥0 }
floating_rate_no_charge: { type: boolean, constraint: REQUIRED, semantics: "RBI mandate: floating-rate retail no prepayment charge" }
disbursement:
estimated_sanction_days: { type: int, constraint: REQUIRED, 1-30 }
estimated_disbursement_days_post_sanction: { type: int, constraint: REQUIRED, 1-30 }
disbursement_mode: { type: enum, constraint: REQUIRED, STRICT ENUM §6, values: [neft, rtgs] }
tranche_based: { type: boolean, constraint: REQUIRED, semantics: "TRUE for construction / plot+construction" }
max_tranches: { type: int, constraint: REQUIRED, 1-12 }
features:
overdraft_facility_available: { type: boolean, constraint: REQUIRED }
overdraft_facility_charge_pct: { type: float, constraint: REQUIRED, 0-1 }
flexible_emi: { type: boolean, constraint: REQUIRED }
step_up_emi_available: { type: boolean, constraint: REQUIRED }
top_up_loan_available_after_months: { type: int, constraint: REQUIRED, ≥0 }
balance_transfer_supported: { type: boolean, constraint: REQUIRED }
pmay_eligibility:
is_eligible_pmay: { type: boolean, constraint: REQUIRED }
pmay_category: { type: enum, constraint: REQUIRED nullable, STRICT ENUM §6, values: [ews, lig, mig_1, mig_2, none] }
estimated_subsidy_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
validity_minutes: { type: int, constraint: REQUIRED, 60-86400 }
hard_pull_required_on_acceptance: { type: boolean, constraint: REQUIRED }
key_fact_statement_url: { type: string, constraint: REQUIRED, HTTPS URL }
loan_agreement_template_url: { type: string, constraint: REQUIRED, HTTPS URL }
partner_reference:
source: { type: string, constraint: REQUIRED }
deeplink: { type: string, constraint: REQUIRED, HTTPS URL }
ValuationSchedule
ValuationSchedule:
schedule_id: { type: string, constraint: REQUIRED }
application_id: { type: string, constraint: REQUIRED }
legal_valuation:
scheduled_at: { type: string, constraint: REQUIRED, ISO_DATETIME }
valuer_firm: { type: string, constraint: REQUIRED }
valuer_contact_phone: { type: string, constraint: REQUIRED, E.164 }
expected_completion_at: { type: string, constraint: REQUIRED, ISO_DATETIME }
technical_valuation:
scheduled_at: { type: string, constraint: REQUIRED, ISO_DATETIME }
valuer_firm: { type: string, constraint: REQUIRED }
valuer_contact_phone: { type: string, constraint: REQUIRED, E.164 }
expected_completion_at: { type: string, constraint: REQUIRED, ISO_DATETIME }
is_combined_visit: { type: boolean, constraint: REQUIRED, semantics: "Single visit covering both" }
documents_required_at_visit: { type: array<string>, constraint: REQUIRED, may NOT be empty }
SanctionResult
SanctionResult:
application_id: { type: string, constraint: REQUIRED }
offer_id: { type: string, constraint: REQUIRED }
sanction_letter_url: { type: string, constraint: REQUIRED, HTTPS URL }
sanctioned_amount_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
sanctioned_ltv_pct: { type: float, constraint: REQUIRED, 0-90 }
sanctioned_tenure_months: { type: int, constraint: REQUIRED, 36-360 }
sanctioned_interest_rate_pct: { type: float, constraint: REQUIRED, 0-15 }
sanctioned_emi_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
legal_clearance_status:
type: enum
constraint: REQUIRED, STRICT ENUM §6
values: [clear, observations_resolvable, encumbrance_flagged, title_unclear]
technical_clearance_status:
type: enum
constraint: REQUIRED, STRICT ENUM §6
values: [clear, minor_observations, major_observations, declined]
sanction_valid_until: { type: string, constraint: REQUIRED, ISO_DATE }
conditions_precedent: { type: array<string>, constraint: REQUIRED, may be empty }
DisbursementResult
DisbursementResult:
application_id: { type: string, constraint: REQUIRED }
loan_account_number: { type: string, constraint: REQUIRED }
tranche_number: { type: int, constraint: REQUIRED, 1-12 }
total_tranches_for_application: { type: int, constraint: REQUIRED, 1-12 }
disbursed_amount_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
cumulative_disbursed_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
beneficiary_name: { type: string, constraint: REQUIRED, semantics: "Builder / seller, NOT applicant" }
beneficiary_account_last4: { type: string, constraint: REQUIRED }
disbursed_at: { type: string, constraint: REQUIRED, ISO_DATETIME }
utr_reference: { type: string, constraint: REQUIRED }
first_emi_date: { type: string, constraint: REQUIRED, ISO_DATE }
emi_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
emi_schedule_url: { type: string, constraint: REQUIRED, HTTPS URL }
loan_agreement_signed_url: { type: string, constraint: REQUIRED, HTTPS URL }
CancellationResult
CancellationResult:
application_id: { type: string, constraint: REQUIRED }
cancelled_at: { type: string, constraint: REQUIRED, ISO_DATETIME }
status: { type: enum, constraint: REQUIRED, STRICT ENUM §6, values: [cancelled_pre_sanction, cancelled_post_sanction_pre_disbursement, cancellation_failed_post_disbursement] }
refund_amount_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
refund_breakdown:
processing_fee_refundable_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
valuation_fee_refundable_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
cersai_franking_refundable_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
refund_eta_days: { type: int, constraint: REQUIRED, 0-45 }
FORBIDDEN FIELDS
paid_placement_score,ad_bid,sponsored_rank,kickback_amountartificial_urgency_text("Rate goes up tomorrow!" without RBI / lender notification)ai_generated_photofor lender / valuer imageryinterest_rate_displayed_excluding_fees(APR mandatory)mandatory_insurance_bundle(RBI 2023 prohibits)editor_recommended,tomo_pick,best_for_first_home_buyercommission_padded_processing_feeinflated_market_valuefor property (RICS / lender-empanelled valuer required)pre_sanction_letter_without_underwriting(regulator-flagged practice)
SECTION 6 — CONTROLLED VOCABULARIES
loan_purpose:
values:
purchase: "Ready / under-construction property purchase"
construction: "Construction on owned plot"
plot_purchase: "Plot only"
plot_plus_construction: "Plot + construction combined"
balance_transfer: "Transfer existing home loan to new lender"
top_up_on_existing: "Top-up on existing home loan"
loan_against_property: "LAP (own residential / commercial)"
renovation: "Major renovation; up to ₹15L typically"
primary_applicant.employment.type:
values:
salaried_corporate, salaried_government, salaried_psu,
self_employed_professional, self_employed_business, retired
primary_applicant.employment.industry:
values:
information_technology, financial_services, manufacturing, retail,
healthcare, education, government, defence, hospitality, real_estate,
media_entertainment, agriculture, logistics, energy, telecom, e_commerce,
consulting, legal_services, other
primary_applicant.employment.company_category:
values: [listed_or_psu, private_ltd_top_tier, private_ltd_other, partnership_or_llp, proprietorship]
co_applicants[].relationship_to_primary:
values: [spouse, parent, child, sibling]
property.property_type:
values:
ready_apartment, ready_independent_house, ready_villa,
under_construction_apartment, under_construction_villa,
resale_apartment, resale_independent_house,
plot_residential, plot_with_construction_plan,
commercial_office, commercial_shop
property.occupancy_status:
values:
self_occupied_immediate, self_occupied_post_disbursement,
rented_out, intended_rental, vacant
property.state: [AP, AR, AS, BR, CG, GA, GJ, HR, HP, JH, KA, KL, MP, MH, MN, ML, MZ, NL, OD, PB, RJ, SK, TN, TS, TR, UP, UK, WB, AN, CH, DN, DD, DL, JK, LA, LD, PY]
loan_request.rate_type_preference / rate_type:
values:
floating: "Linked to benchmark (EBLR / MCLR)"
fixed: "Fixed for full or fixed period"
hybrid: "Fixed for first N years, floating thereafter"
rate_benchmark:
values: [eblr, mclr, base_rate_legacy, fixed_promised]
loan_request.first_emi_date_preference: [salary_date, mid_month, custom_date]
lender_type:
values: [scheduled_commercial_bank, housing_finance_company_nhb, small_finance_bank, nbfc_systemic, nbfc_other]
disbursement_mode: [neft, rtgs]
pmay_category: [ews, lig, mig_1, mig_2, none]
legal_clearance_status: [clear, observations_resolvable, encumbrance_flagged, title_unclear]
technical_clearance_status: [clear, minor_observations, major_observations, declined]
CancellationResult.status:
values: [cancelled_pre_sanction, cancelled_post_sanction_pre_disbursement, cancellation_failed_post_disbursement]
SECTION 7 — TTBS DIMENSIONS
TIME (weight = 0.15):
signals_used:
- is_pre_approved
- estimated_sanction_days
- estimated_disbursement_days_post_sanction
weighting:
pre_approved: 0.45
sanction_speed: 0.35
disbursement_speed: 0.20
TASTE (weight = 0.10):
signals_used:
- lender matches preferred_lenders
- existing bank relationship
- lender_type matches user preference
weighting:
preferred_lender: 0.50
existing_bank: 0.35
lender_type_pref: 0.15
BUDGET (weight = 0.40):
signals_used:
- apr_pct (primary)
- interest_rate_pct
- fees aggregate
- prepayment_terms (floating preferred when no-charge)
- pmay_eligibility (when eligible, subsidy materially shifts ranking)
weighting:
apr: 0.60
fees: 0.20
prepay_flex: 0.10
pmay_subsidy: 0.10
SAFETY (weight = 0.35):
signals_used:
- lender.lender_type (scheduled bank > HFC > NBFC)
- lender.ratings (investment-grade preferred)
- lender.rbi_registration / nhb_registration current
- key_fact_statement_url present and compliant
- balance_transfer / top-up policies favourable (option-value over 20y tenure)
- features.overdraft_facility_available (interest-saving optionality)
weighting:
lender_type: 0.35
ratings: 0.20
regulator_status: 0.15
kfs_compliant: 0.10
long_term_flexibility: 0.10
overdraft_option: 0.10
user_band_handling:
fast: scheduled bank or major HFC with A-rating
balanced: scheduled bank with A-rating
great: scheduled bank with AAA rating only
Locked weights per finance.apply_home_loan: time 0.15 / taste 0.10 / budget 0.40 / safety 0.35. APR variance compounded over 20-30y tenure makes Budget dominant; long-tenure relationship makes Safety material.
SECTION 8 — COMPLETION CONTRACT
POST /api/v1/cpc/mcp_provider/<your_partner_id>
Body:
{
"intent": "finance.apply_home_loan",
"external_id": "<application_id>",
"request_id": "<request_id>",
"amount_inr": 32500, // NET partner / DSA commission (typically 0.5% of disbursed)
"gst_inr": 5850,
"tips_inr": 0,
"pass_through_inr": 6500000, // disbursed loan amount; goes to builder / seller
"closed_at": "2026-06-20T11:20:00+05:30",
"status": "completed",
"lender_id": "hdfc_bank",
"loan_amount_disbursed_inr": 6500000,
"tenure_months": 240,
"apr_pct": 9.05,
"ltv_pct": 76.5,
"is_pmay_eligible": false
}
For tranche-based disbursement (construction loans), partners POST a completion per tranche with the per-tranche commission.
HMAC-SHA256, 5-min replay, NET-only commission.
SECTION 9 — WIDGET
HomeLoanWidget (planned). Interim: comparison ListingsWidget.
Field mapping:
- HomeLoanOffer.lender.name + logo → header
- lender_type → eyebrow ("Scheduled Bank" / "HFC")
- apr_pct → big price ("X% APR")
- interest_rate_pct → "Rate X%"
- emi_inr → "EMI ₹X" pill
- tenure_months → "X yrs" pill
- ltv_pct → "LTV X%" pill
- is_pre_approved → green "Pre-approved" badge
- prepayment_terms.floating_rate_no_charge → "Free prepayment" badge
- features.overdraft_facility_available → "Overdraft" pill
- pmay_eligibility.is_eligible_pmay → green "PMAY ₹X subsidy" badge when eligible
- key_fact_statement_url → "View KFS" link
SECTION 10 — CACHING POLICY
| Call | TTL | Rationale |
|---|---|---|
| search_home_loan_offers | 10min | Offers stable for short window |
| initiate_application_and_valuation | NO CACHE | — |
| schedule_valuation_visits | NO CACHE | Live calendar |
| accept_sanction_and_disburse | NO CACHE | Single-shot |
| cancel_pre_disbursement | NO CACHE | — |
| Lender static (ratings, registration) | 24h | — |
| KFS / Agreement templates | 7d | Versioned |
SECTION 11 — ERROR CODES
| Code | HTTP | Meaning | Retry |
|---|---|---|---|
INVALID_REQUEST |
400 | Malformed | No |
RATE_LIMITED |
429 | Throttle | 1, 2s |
INTERNAL_ERROR |
500 | Partner failure | 2, exp |
SIGNATURE_INVALID |
401 | HMAC fail | No |
CREDIT_BUREAU_CONSENT_MISSING |
422 | No bureau consent | No |
THIN_BUREAU_FILE |
422 | Insufficient credit history | No |
AGE_OUT_OF_RANGE |
422 | Applicant age outside lender band | No |
INCOME_BELOW_THRESHOLD |
422 | Net income below lender floor | No |
EMPLOYER_NOT_COVERED |
422 | Employer outside approved list | No |
FOIR_EXCEEDED |
422 | FOIR cap exceeded | No |
LTV_EXCEEDED |
422 | LTV ask above RBI cap | No (UI lowers ask) |
PROPERTY_TYPE_NOT_FUNDED |
422 | Lender doesn't fund this property type | No |
PROPERTY_CITY_NOT_SERVICED |
422 | Pincode outside lender geography | No |
RERA_REGISTRATION_MISSING |
422 | Under-construction without RERA | No |
RERA_REGISTRATION_INVALID |
422 | RERA number not found / expired | No |
LEGAL_CLEARANCE_FAILED |
422 | Title unclear / encumbrance flagged | No |
TECHNICAL_CLEARANCE_FAILED |
422 | Property fails construction norms | No |
KYC_FAILED |
422 | KYC mismatch | No |
BANK_ACCOUNT_INVALID |
422 | IFSC / account invalid | No |
LENDER_DOWN |
503 | Lender API unavailable | 1 retry, 2s |
OFFER_EXPIRED |
410 | Past validity | No |
SANCTION_EXPIRED |
410 | Past sanction validity | No |
CONDITIONS_PRECEDENT_PENDING |
422 | Disbursement blocked till satisfied | No |
SECTION 12 — SANDBOX → PRODUCTION CHECKLIST
[ ] All five tools implemented
[ ] At least 6 lenders (mix of scheduled banks + HFCs)
[ ] All RBI / NHB registration numbers verifiable
[ ] APR includes ALL fees per RBI KFS Master Direction
[ ] LTV caps respected per RBI norms (90/80/75% by loan amount band)
[ ] key_fact_statement_url returns RBI-compliant KFS
[ ] No mandatory insurance bundle (RBI 2023)
[ ] Floating-rate retail: no prepayment charge
[ ] Soft pull at quote; hard pull on acceptance only
[ ] Legal + technical valuation by lender-empanelled valuers (not partner-affiliated)
[ ] RERA registration verified for under-construction property
[ ] PMAY eligibility checked correctly (income / property / area criteria)
[ ] Tranche-based disbursement for construction loans
[ ] All controlled vocabularies respected
[ ] HMAC signing verified
[ ] amount_inr in CPC is partner COMMISSION only (NET), NOT disbursed
[ ] pass_through_inr captures disbursed amount to builder / seller
[ ] No forbidden fields anywhere
[ ] No "Top Pick" / "Recommended" badges
[ ] SLA p95 met
[ ] DSA agreements with each lender uploaded
[ ] Compliance: GSTIN, DSA agreements, privacy policy, grievance officer
[ ] Customer support: grievance escalation matrix per RBI ombudsman framework
[ ] DPDP Act compliance: explicit consent for AA / bureau / property docs
SECTION 13 — ANTI-FABRICATION RULES
RULE 1: No paid_placement / ad / kickback fields. Home loan DSA
commissions are smaller % (0.3-0.7%) but larger absolute rupee
amounts; bias risk is real. TOMO audits monthly.
RULE 2: apr_pct MUST include processing fee, legal / tech valuation
fee, CERSAI, franking, stamp duty, and any mandatory insurance
per RBI KFS Master Direction. Misstating APR by hiding fees =
immediate suspension.
RULE 3: key_fact_statement_url must return RBI-compliant KFS for the
specific offer. Marketing brochures = suspension.
RULE 4: insurance_premium_bundled_inr cannot be non-zero unless user
explicitly opted in. RBI 2023 prohibits mandatory bundling.
RULE 5: prepayment fields must comply with RBI's floating-rate retail
rule: zero prepayment charge for individual floating-rate
home loans. Misstating = customer-harm.
RULE 6: ltv_pct cannot exceed RBI cap (90% up to ₹30L; 80% ₹30-75L;
75% above ₹75L; 60% for plot-only). Above cap = invalid.
RULE 7: lender.lender_type, rbi_registration_number, and
nhb_registration_number must accurately reflect regulator
records.
RULE 8: rate_benchmark must reflect actual product structure (EBLR
per RBI Oct-2019 mandate for floating retail). Misstating
benchmark = regulatory breach.
RULE 9: rate_spread_pct reset behaviour must follow lender's
published policy; surprise spread hikes = customer-harm +
suspension.
RULE 10: Legal + technical valuation must be done by lender-
empanelled (or RICS-registered) valuers — NOT partners or
partner-affiliated firms (conflict of interest).
RULE 11: Sanction without underwriting (purely marketing letters
labelled "sanction") = regulatory breach + suspension.
RULE 12: Disbursement to builder / seller account ONLY (not to
applicant); for construction, only against verified work
milestone. Diverting funds = fraud + immediate suspension.
RULE 13: artificial_urgency_text forbidden ("EBLR moves tomorrow!"
without RBI notification).
RULE 14: No AI-generated lender / valuer imagery.
RULE 15: amount_inr in CPC is partner / DSA commission only — NEVER
disbursed loan amount.
RULE 16: No "Top Pick" / "Best for First Home Buyer" badges. Lending
recommendation is regulated; TOMO orchestrates source-blind
TTBS only.
RULE 17: information_completeness_score (hidden ranking factor,
weight 0.10) rewards full §5 shape.
RULE 18: PMAY eligibility flag must reflect actual eligibility per
current PMAY 2.0 criteria (income, property type, carpet
area, beneficiary norms). Misstating = customer-harm + GoI-
programme breach.
RULE 19: Fees disclosed in §5 must match KFS exactly. Surprise
charges at sanction or disbursement = immediate suspension.
RULE 20: For balance-transfer loans, partners cannot quote without
the existing loan's foreclosure / handover discharge plan
being documented and verifiable.
VERSION HISTORY
v1.0.0 — 2026-05-13 — Initial spec. Purchase, construction, plot, BT,
top-up, LAP under one intent via loan_purpose.
APR per RBI KFS. LTV caps per RBI norms. PMAY
eligibility surfaced as material rank shifter
when applicable. NET commission base. Budget-
and-Safety dominant TTBS reflecting tenure-
compounded impact.