Skip to content

18.1 LOS overview and state machine

The Loan Origination System covers the end-to-end journey from lead to disbursed loan. After disbursement, the loan moves to the LMS (18.3).

LOS responsibilities:

  1. Lead acquisition and channel attribution.
  2. Application capture with all data.
  3. KYC / KYB completion.
  4. Data ingestion (bureau, GST, BSA, AA, MCA, Tally).
  5. Underwriting decisioning — rule + scorecard engine.
  6. Manual review workflow for refer cases.
  7. Deviation approval workflow.
  8. Sanction issuance.
  9. Document generation (KFS, agreement, DPN, PG).
  10. eSign + eStamp orchestration.
  11. NACH / eNACH mandate activation.
  12. Pre-disbursement checklist enforcement.
  13. Disbursement execution.
  14. Handoff to LMS.

The application’s primary states:

LEAD — captured but not converted
DRAFT — application started, not submitted
SUBMITTED — borrower submitted
KYC_IN_PROGRESS — KYC workflows running
INGESTION_IN_PROGRESS — data ingestion running
UNDER_REVIEW — decisioning + manual review
APPROVED — decision approved
DEVIATION_PENDING — awaiting deviation approval
DECLINED — decision declined
REFERRED_TO_COMMITTEE — escalated to credit committee
WITHDRAWN — borrower withdrew
EXPIRED — sanction validity lapsed without disbursement
OFFER_ACCEPTED — borrower accepted offer
DOCS_GENERATED — documents created
ESIGN_IN_PROGRESS — multi-signer eSign running
DOCS_EXECUTED — all docs signed and stamped
MANDATE_ACTIVE — NACH / eNACH active
DISBURSED — funds released, UTR captured
HANDED_OFF_TO_LMS — terminal LOS state
LEAD ──qualify──→ DRAFT
DRAFT ──save──→ DRAFT (loop)
DRAFT ──submit──→ SUBMITTED
SUBMITTED ──auto──→ KYC_IN_PROGRESS
KYC_IN_PROGRESS ──auto──→ INGESTION_IN_PROGRESS (parallel with KYC)
KYC_IN_PROGRESS + INGESTION_IN_PROGRESS ──all-complete──→ UNDER_REVIEW
UNDER_REVIEW ──engine APPROVE──→ APPROVED
UNDER_REVIEW ──engine DECLINE──→ DECLINED
UNDER_REVIEW ──engine REFER + analyst recommend approve──→ APPROVED
UNDER_REVIEW ──engine REFER + analyst decline──→ DECLINED
UNDER_REVIEW ──engine REFER + analyst recommend deviation──→ DEVIATION_PENDING
DEVIATION_PENDING ──approved──→ APPROVED
DEVIATION_PENDING ──declined──→ DECLINED
DEVIATION_PENDING ──escalated──→ REFERRED_TO_COMMITTEE
REFERRED_TO_COMMITTEE ──approved──→ APPROVED
REFERRED_TO_COMMITTEE ──declined──→ DECLINED
APPROVED ──borrower accept──→ OFFER_ACCEPTED
APPROVED ──validity lapse──→ EXPIRED
OFFER_ACCEPTED ──auto──→ DOCS_GENERATED
DOCS_GENERATED ──borrower sign──→ ESIGN_IN_PROGRESS
ESIGN_IN_PROGRESS ──all signers complete──→ DOCS_EXECUTED
DOCS_EXECUTED ──auto──→ MANDATE_ACTIVE (requires NACH ack)
MANDATE_ACTIVE ──pre-disb checklist + execute──→ DISBURSED
DISBURSED ──auto──→ HANDED_OFF_TO_LMS
[any state] ──borrower withdraw──→ WITHDRAWN

Triggering events (the verbs that move state)

Section titled “Triggering events (the verbs that move state)”
EventFrom → ToSource
lead.qualifiedLEAD → DRAFT (implicit on app creation)Sales / pre-app
application.section_savedDRAFT loopBorrower
application.submittedDRAFT → SUBMITTEDBorrower
kyc.individual.completed (per promoter)KYC_IN_PROGRESS conditionKYC module
kyb.entity.completedKYC_IN_PROGRESS conditionKYC module
data.bank_statement.parsedINGESTION conditionIngestion
data.gst.pulledINGESTION conditionIngestion
data.bureau.pulledINGESTION conditionIngestion
decision.run.completedUNDER_REVIEW state updateDecision engine
decision.approvedUNDER_REVIEW → APPROVEDEngine / manual
decision.declinedUNDER_REVIEW → DECLINEDEngine / manual
decision.referredUNDER_REVIEW remainsEngine
deviation.approvedDEVIATION_PENDING → APPROVEDApprover
deviation.declinedDEVIATION_PENDING → DECLINEDApprover
offer.acceptedAPPROVED → OFFER_ACCEPTEDBorrower
sanction.issued(concurrent with OFFER_ACCEPTED)LOS
document.generatedOFFER_ACCEPTED → DOCS_GENERATEDDocumentation
kfs.acknowledged(pre-condition for eSign on agreement)Borrower
esign.completed (per signer)ESIGN_IN_PROGRESS state updateeSign vendor
esign.all_completedESIGN_IN_PROGRESS → DOCS_EXECUTEDLOS
mandate.active(concurrent with DOCS_EXECUTED)NACH adapter
disbursement.executed + utr.capturedMANDATE_ACTIVE → DISBURSEDDisbursement
loan.activatedDISBURSED → HANDED_OFF_TO_LMSLMS
application.withdrawn* → WITHDRAWNBorrower
sanction.expiredAPPROVED / OFFER_ACCEPTED → EXPIREDAuto-scheduler
  • KYC orchestration kicked off.
  • Ingestion orchestration kicked off.
  • Sales channel attribution finalised.
  • Lead converted (lead.status = converted).
  • All promoter KYC complete.
  • KYB entity verification complete.
  • Sanctions screening complete.
  • BO graph complete.
  • Decision engine invoked.
  • sanction row created (LMS-readable).
  • Offer expiry timer set (typically 15 – 30 days).
  • Borrower notified (SMS + WhatsApp + email).
  • KFS preview generated (not yet acknowledged).
  • Documentation orchestration kicked off.
  • KFS finalised.
  • Agreement, DPN, PG templates rendered.
  • All documents in DMS.
  • Evidence package partially assembled.
  • Mandate activation awaited.
  • NACH activation confirmed by sponsor bank.
  • Pre-disbursement checklist becomes accessible to ops.
  • loan_account row created (in LMS).
  • LMS schedule generated.
  • LMS daily accrual begins.
  • Borrower notified with UTR.
  • Channel partner notified.
  • Co-lending partner notified (if applicable).
  • Insurance triggered (if bundled).

Multiple transitions can be in progress simultaneously:

  • KYC for Director 1 and Director 2 run in parallel.
  • KYC and Ingestion run in parallel.
  • eSign signers can act in parallel (per agreement design).
  • Document generation and mandate activation can run in parallel.

The LOS state machine uses a workflow engine (5.5) to manage these parallel paths and the rendezvous (e.g., “all KYC complete and all ingestion complete = move to UNDER_REVIEW”).

  • One promoter’s KYC fails → workflow waits for re-attempt.
  • Multiple failures → REFER to manual.
  • Permanent failure → DECLINE.
  • AA fetch fails → fallback to PDF upload.
  • GST OTP fails → reschedule.
  • Bureau no-hit → REFER if borrower has no bureau record at all.
  • Engine returns error or timeout → REFER.
  • Deviation pending for too long → escalate or auto-decline.
  • Single signer fail → switch vendor or paper.
  • Repeated failures → manual handling.
  • NACH rejection by sponsor bank → re-register with corrected details.
  • Payout rail rejection → re-attempt or escalate.
  • Returned funds → reverse and re-attempt.
TransitionTarget time
SUBMITTED → APPROVED (auto path)< 6 hours typical for standard A-grade
SUBMITTED → APPROVED (manual review)< 5 days p95
APPROVED → OFFER_ACCEPTEDBorrower-dependent (typically 1 – 7 days)
OFFER_ACCEPTED → DOCS_GENERATED< 30 minutes
DOCS_GENERATED → DOCS_EXECUTEDBorrower-dependent (typically 4 – 24 hours for eSign multi-signer)
DOCS_EXECUTED → MANDATE_ACTIVE< 6 hours (depends on sponsor bank NACH cycle)
MANDATE_ACTIVE → DISBURSED< 1 hour after checklist clearance
DISBURSED → HANDED_OFF_TO_LMS< 5 minutes (automated)

Every state transition emits an audit.event:

  • Actor (user / service).
  • From state, to state.
  • Reason / event reference.
  • Timestamp.
  • IP, device (where user-driven).

Audit chain (5.13) makes tampering detectable.

Every state-changing API call is idempotency-keyed:

  • Re-submission of application.submit after first success returns the same state, no double-processing.
  • offer.accept similarly.
  • disbursement.execute critically — duplicate calls do not double-disburse.
  • No skip states — transitions follow the diagram; jumping is not permitted.
  • No state without event — every state change is event-driven and audited.
  • All pre-conditions (e.g., KYC complete + ingestion complete + decision approved) must be satisfied before downstream state.
  • Concurrent paths properly synchronised via workflow engine.
  • Failure paths explicit; no silent state hangs.