Internal Reference · WhatsApp Lending Platform

System Flows

How a WhatsApp message becomes a loan disbursement, a repayment, or a timely reminder — and what happens under the hood at each step. Tap the buttons inside each chat to walk through the linked web flows.

Flow 01

Onboarding

Unknown contact → verified borrower

No one can engage the system without being explicitly invited by an admin. Once invited, the borrower completes KYC and sets a PIN before their first session.

Flowchart · onboarding gate
InboundWhatsApp msg Invited?Redis · invited Admin runs INVITE KYC formname · NIDA · income PIN setupPBKDF2 600k Borrower registeredlimit TZS 4,000 no invite yes / known
1
Language selection
First message triggers a bilingual prompt. Reply 1 for English, 2 for Kiswahili. Language preference is stored in Redis and auto-detected from Swahili keywords in future messages.
Redis · lang_pref
2
Invite gate
Unknown contacts cannot proceed. Admin receives a WhatsApp notification with the phone number and first message, then runs INVITE 255XXXXXXXXX to unlock the number.
Admin WA notificationRedis · invited
3
Onboarding web form
A one-time tokenised link (10 min TTL) opens a KYC form in the WhatsApp in-app browser. Captures: full name, NIDA number, phone, monthly income, employer.
Redis · onboarding_token (10 min)
4
PIN setup
After KYC form submission, a second link issues the PIN setup flow. PBKDF2-SHA256 (600k iterations) hash stored in Redis. All future sessions require PIN verification within a 24-hour sliding window.
PBKDF2-SHA256 · 600k iterationsRedis · pin, pin_verified (24h)
5
Borrower registered
Phone added to the borrower contact set. All subsequent messages route through the full pipeline. Credit limit initialised at TZS 4,000 (Tier 1).
Redis · borrower_contactsCredit limit: TZS 4,000
Flow 02

Loan Application

Conversation → underwriting → disbursement

An AI agent collects the application in natural language, then a deterministic underwriting pipeline scores it and routes the outcome to one of three paths: auto-approve, credit officer review, or rejection.

Flowchart · underwriting decision
PIN gate24h session Collect (AI)Mastra agent Face livenessRekognition Score?0–100 Auto-approve → disburseFineract + Malipo payout HITL reviewcredit officer decides Rejectborrower + officer notified ≥70% 40–69% <40%
Underwriting checks (run in sequence)
Identity · face liveness (NIDA fallback)
Fraud watchlist
Credit report (emulated)
DTI calculation
Confidence score (0–100)
1
PIN gate
Every session that isn't already verified sends a PIN link. Verified sessions slide the 24-hour TTL. Three wrong attempts trigger a 30-minute lockout.
24h session · 30 min lockout
2
AI agent collects application
The Loan Originator agent gathers: full name, NIDA number, monthly income, employer, loan purpose, amount, and tenor. New borrowers no longer upload a NIDA photo — identity is confirmed by a face-liveness selfie after the application completes. Returning verified borrowers skip identity re-verification. Credit limit and tier are injected as context.
Mastra AI agentConversation history in session
3
Face liveness (new borrowers) Updated
Once the application is submitted, new borrowers get a one-time link to a quick selfie. AWS Rekognition runs a liveness check plus a face match and returns a band — pass, review, or fail. A pass is accepted as identity proof and underwriting resumes automatically. The application is parked in Redis while the borrower completes the selfie. Returning verified borrowers skip this; the NIDA card photo is no longer required.
AWS Rekognition liveness + CompareFacesBand: pass / review / failRedis · face_pending_app (1h)
4
Approval gateway → 3 outcomes
The confidence score routes the application. KYC failure or watchlist hit forces the score to zero regardless of other factors. DTI >50% and weak credit score each subtract points.
≥70% AUTO_APPROVE40–69% HITL_PAUSE<40% REJECT
Auto-Approve
≥ 70%
Straight-through processing
  • Loan created in Fineract
  • Approved & activated
  • Borrower picks disbursement number (YES or alternate)
  • PIN re-auth web form
  • Malipo Pay payout (create + approve)
  • WhatsApp confirmation sent
HITL Pause
40–69%
Credit officer reviews
  • Loan parked in Fineract (HITL Checkpoint 1)
  • Credit officer receives full context via WA
  • Manual approve → triggers disbursement
  • Manual reject → borrower notified
  • Loans ≥ TZS 5,000,000 always go here regardless of score
Reject
< 40%
Application declined
  • Borrower notified via WhatsApp
  • Credit officer receives rejection summary
  • Key risk factors logged (KYC fail, watchlist, DTI, credit score)
Flow 03

Repayment

PAY → Fineract: three paths, one outcome

After a Malipo STK push is sent, three independent processes race to confirm payment and record it — so a missed webhook never leaves a borrower without confirmation.

Flowchart · three confirmation paths
PAY+ amount? Select loanif > 1 active STK pushMalipo collection Webhookimmediate callback Active poller30s × 10 = 5 min Reconciler cron*/2 * * * * Record + notifyidempotent · Fineract · WA
1
PAY command received
Borrower sends PAY (or LIPA, LIPIA, REPAY). An optional amount can follow: PAY 2000.
2
Loan selection
1 active loan → proceed directly. Multiple active loans → numbered list sent to borrower, selection stored in Redis for 10 minutes.
Redis · pay_select (10 min)
3
Malipo STK push
Malipo Pay collection initiated. Reference (e.g. MU00109) and loan mapping saved to Redis. Borrower receives a mobile money prompt on their handset.
POST /api/v2/payment/collectionRedis · malipo_coll (24h)
4
Payment confirmed (any of 3 paths)
First path to confirm claims an atomic idempotency key. All three paths record repayment in Fineract, check credit limit tier, and send the borrower a WhatsApp confirmation.
Fineract repayment recordedCredit limit checkWhatsApp notification
Webhook
Malipo calls back POST /webhooks/collections
Phone resolved from malipo_coll: mapping if omitted from payload
Claims idempotency key → records repayment → notifies borrower
Timing: immediate on payment
Active Poller
Fires immediately after STK push
Polls GET /api/v2/payment?reference= every 30 seconds
Stops on first SUCCESSFUL status or after 10 attempts
Window: 30s × 10 = 5 minutes
Reconciler Cron
Scans Redis for all malipo_coll:* keys
Skips any reference with an idempotency key already set
Polls Malipo for terminal status → processes & notifies
Schedule: */2 * * * * (every 2 min)
All three paths → recordRepayment → notifyBorrower
Flow 04

Reminders & Escalation

Two daily jobs, one goal: no surprises

Every morning two cron jobs sweep the portfolio. One sends same-day due reminders; the other escalates loans already in arrears before the credit team starts their day.

Flowchart · two morning cron lanes
08:00 07:10 Active loansstatus 300 Due today?dueDate = today Send WA reminderSMS fallback Borrower notified yes Arrears loansinArrears = true Escalated?arrears_esc:{id} Final reminder+ HITL officer alert Credit officer no
08:00
Repayment Reminders
0 8 * * * · Africa/Dar_es_Salaam
1
Query Fineract for all active loans (status 300), fetch repayment schedules in parallel batches of 20.
2
For each loan, find a repayment period where dueDate = today and the period is not yet complete.
3
Fetch the client record to get mobile number, then send via WhatsApp with SMS as fallback.
WhatsApp message (EN)
Hi Harvey Kadyanji! Your loan repayment is due today. Amount: TZS 2,508 Loan ref: 35 Please pay on time to avoid penalties. Send PAY to make your payment.
07:10
Overdue Escalation
10 7 * * * · Africa/Dar_es_Salaam
1
Query Fineract for loans where inArrears = true. Runs 10 minutes after risk-hunter (07:00) to avoid competing DB load.
2
Checks Redis for escalation state (arrears_esc:{loanId}) to avoid re-escalating loans already in the queue.
3
Sends a final reminder to the borrower and a HITL notification to the credit officer with outstanding amount, days overdue, and loan details.
Credit officer alert
Overdue escalation Borrower: Harvey Kadyanji (255744…) Loan: 35 · TZS 2,508 outstanding Days overdue: 3 Action: review or initiate collection
Other scheduled jobs
06:00  Compliance audit
07:00  Risk hunter
08:05  Portfolio watchdog
07:00 monthly  Board report
*/2 min  Collections reconciler