Inspiration
In Canadian mortgage brokering, the first 24 hours after an inquiry decide whether a borrower stays. Brokers spend that time on the same chores: check whether the file passes the stress test, work out which type of lender fits, and, for renewals, explain a prepayment penalty that nobody understands. Meanwhile the borrower hears nothing. Automating the outreach is risky, because a regulated mortgage message can't quote a rate, promise an approval or guarantee anything. I wanted something that does the triage and the messaging together, and stays inside those limits.
What it does
MortgageLoanOps combines three tools I had been building separately:
- LendOps: the OSFI B-20 stress test, GDS/TDS ratios, the insured-mortgage rules in force since Dec 15, 2024 ($1.5M cap, 30-year amortization for first-time buyers and new builds), and matching against lender categories.
- IRD: the prepayment penalty (the greater of three months' interest and the interest-rate differential) and a break-even check on whether refinancing pays off.
- Benchmark: an indicative home value, found by indexing a purchase price with regional price curves.
Then it messages the borrower through AWS End User Messaging SMS, End User Messaging Social (WhatsApp) and Amazon SES, with a 5-second timeout on each channel and a secure-portal fallback. Every message passes a guardrail first that blocks rate quotes, approval promises and guarantees. Inbound replies are handled too (STOP/START/HELP and a broker call-back request), and a Bedrock agent answers questions by calling the real calculators. It never does the maths itself.
How I built it
Python 3.10+ with no runtime dependencies in dry-run mode. boto3 is only needed for live AWS mode. The AWS calls are SendTextMessage, SendWhatsAppMessage, SendEmail and Bedrock Converse tool use. There are Lambda handlers and a SAM template for deployment.
Canadian fixed mortgages compound semi-annually, so the monthly rate is
$$i = \left(1 + \frac{r}{2}\right)^{1/6} - 1, \qquad P = L \cdot \frac{i}{1 - (1+i)^{-n}}$$
For a $600,000, 25-year mortgage that gives \$3,490 a month at 5% and \$4,202 at the 7% stress rate.
Challenges
- A wrong shortcut. My first stress test scaled the payment in a straight line with the rate. That overstated the stressed payment by about 14–19% on a typical file. I replaced it with the true annuity formula and wrote a test that fails if the shortcut comes back.
- Compliance versus automation. Guardrails had to run before any AWS call, and I tested that a blocked message makes zero API calls.
- Honest screening. Without a licensed data provider, identity and PEP screening can't be done properly, so the module reports "not screened" instead of pretending to clear anyone.
What I learned
How AWS End User Messaging, Social and SES fit together as one fallback chain, how Bedrock tool use keeps an LLM from inventing numbers, and how useful tests that fail on purpose are for catching your own mistakes.
What's next
Run the SMS and WhatsApp paths on a live account once numbers are registered, connect a licensed screening provider, verify lender policy against real broker panels, and move the agent to the AgentCore runtime.
Limitations
46 automated tests pass, including 10,000-case randomized checks, but they use fake AWS clients. Lender policy is illustrative by category. The home value is an indicative estimate, not an appraisal. This is a prototype for a licensed broker to verify, not lending or legal advice.## Inspiration
What it does
How we built it
Challenges we ran into
Accomplishments that we're proud of
What we learned
What's next for Untitled
Built With
- amazon-bedrock
- amazon-ses
- amazon-sns
- amazon-web-services
- aws-end-user-messaging
- aws-lambda
- aws-sam
- boto3
- fintech
- mortgage
- pytest
- python
- sms

