Appearance
Loan affordability
A personal-loan application decided on affordability: the applicant answers a short flow, four rules check identity, repayments against income, the amount and repeat applications, and borderline files go to an underwriter. Pack: examples/policies/loan-affordability/.
A pattern for expressing a lending & credit policy, not compliance guidance: the thresholds, lists and fields are placeholders chosen to make the example run; a real policy comes from the business's own rules. It calls no app, so it runs in an empty workspace as it is.
The decision it automates
Whether to offer the loan, refer it to an underwriter, or decline it, at the moment the application is submitted.
Data expected
- The applicant as a subject (kind
user) withidentityVerified, the result of your identity check, written by your backend before it starts the run. - The flow's answers under
submission:amount,purpose,employment,employerName,monthlyIncomeand an optional payslip. loan.applicationevents posted throughPOST /eventsfor each application, so the velocity rule can count them.
Steps and rules
| Step | Type | Why |
|---|---|---|
collect | wait_for_collection | The loan-application flow; employed applicants are asked for their employer and a payslip. |
rules | evaluate_rules | The loan-affordability rule set under max_severity: a failed block rule declines, a failed warn rule refers. |
route | branch | rules.outcome == manual_review opens a case. |
review | create_case | loan_underwriting, 48-hour SLA. |
decide | emit_decision | From the rules, or the reviewer's decision. |
The rule set loan-affordability (useCase: underwriting) uses max_severity: a failed block rule rejects, a failed warn rule sends the run to review, and the weights add up to the score.
| Rule | Type | Severity, weight | Fails when |
|---|---|---|---|
loan_identity_verified | comparison | block, 100 | subject.identityVerified is not true |
loan_affordability | expression | warn, 40 | amount / 36 is more than 35% of monthlyIncome |
loan_amount_referral | score threshold | warn, 20 | amount is above 25 000 |
loan_repeat_applications | velocity | warn, 20 | more than one loan.application event in 30 days |
What a reviewer sees
A loan_underwriting case with the application, the optional payslip and each rule's result. The underwriter's decision and note become the decision and its reasons.
How to adapt it
Read the term from the flow instead of assuming 36 months, add a call_app step for your credit bureau (an app you build with the SDK) and rules over its answer, and backtest a new affordability limit over past applications before publishing it. A doc-verify-mock step on the payslip shows the asynchronous document path (Individual KYC with documents).
Run it
bash
pnpm policy:import examples/policies/loan-affordability --publishThe fixture asks for 12 000 on an income of 900: repayments of 333 a month are above the 315 that 35% allows, so the affordability rule fails, a loan_underwriting case opens, the check approves it and the run completes with a manual approve.