Cross-flow timeline
Each row is one persona; each column is a BRD step. Cells show what each persona sees on WhatsApp at that step.
microfinance bank
Bokku
B1: Email to procurement@bokku.ng · B2: WA to procurement manager · B3–B5: Waybill, OTP, ack
B6: Email to finance@bokku.ng · Cc financing partner
Speed budgets (SLA)
Every transition has a wall-clock budget. Breaching any of these in production triggers a P1 page. The rail is only useful if it is fast.
| Transition | Trigger | p95 budget | Failure mode | Critical? |
|---|---|---|---|---|
| First inbound msg → O1 persona picker | Welcome template + 3 reply buttons | ≤ 800ms | User doesn't engage; lost lead | — |
| O1 persona tap → O2 tailored welcome | Pre-rendered persona-variant template | ≤ 600ms | User loses momentum between picker and Flow | — |
| O2 tap → O3 signup Flow opens | Local modal render (no network) | ≤ 200ms | Perceived stutter on the entry tap | — |
| BVN entered → name verified | NIBSS BVN lookup + name fuzzy match | ≤ 1.5s | User types again or abandons | — |
| CAC RC entered → business auto-fill | CAC public registry fetch + cache write | ≤ 1.5s | Form feels stuck; abandonment | — |
| Signup submit → O4 settlement CTA | Account creation + tenant schema + template | ≤ 1.5s | Supplier stalls between two Flows | — |
| O4 tap → O5 settlement Flow opens | Local modal render (no network) | ≤ 200ms | Perceived stutter on the entry tap | — |
| Account number entered → name auto-fills | NIBSS NameEnquiry + BVN fuzzy match (Flow data-source) | ≤ 1.2s | User types again, double-submits, or abandons | — |
| Settlement submit → S1 welcome | Bank link write + transit wallet provisioning + template | ≤ 1s | Supplier abandons before first deal | — |
| Total: first message → ready-to-fund | Sum of all onboarding hops (parallel where possible) | ≤ 2 min | Time-to-value missed; cold lead | CRIT |
| S2 upload → S3 AI confirm | Media download + OpenAI mini extraction | ≤ 1.8s | Perceived “app feels slow” | — |
| S3 confirm → S4 terms screen | Pricing engine + template send | ≤ 600ms | Supplier cancels mid-flow | — |
| S4 accept → B1 procurement email + B2 WA nudge (parallel) | Email send + WA template fan-out | ≤ 30s | Procurement recall drops; fraud window opens | CRIT |
| B3 waybill submitted → vision pass | Vision model + cross-check vs invoice JSON | ≤ 3s | Procurement manager walks away | — |
| B4 OTP entered → ack | OTP validate (sent to corporate email) + state advance | ≤ 500ms | Procurement manager loses confidence in process | — |
| B5 ack → procurement receipt email | Email assembly + send (Bokku procurement audit record) | ≤ 5s | Procurement chases for closure | — |
| DELIVERY_CONFIRMED → F2 financier decision arrives | Notification template send | ≤ 5s | Financier feels out-of-loop on a confirmed deal | — |
| F2 "Approve & fund" tap → F3 wallet instruction | Local screen render with supplier-wallet details | ≤ 600ms | Financier doubts the fund step worked | — |
| F3 confirm → F4 + S6 (WA) + B6 (email to finance) | Capital wallet → supplier wallet transfer + fee deduction + bank remit + 2 templates + 1 email | ≤ 8 min total (NIBSS) | Supplier calls support; buyer finance never sees instructions | CRIT |
| FUNDED event → B6 finance email lands | Email assembly + ESP send + DKIM sign | ≤ 5s | Buyer AP team can't process; ageing starts | CRIT |
| Buyer wallet inbound → S7 (WA) + F4 (WA) + B8 (email to finance) | Wallet webhook + 2 WA templates + 1 receipt email in parallel | ≤ 10s | Supplier & financier anxious; buyer chases | CRIT |
| Cap threshold crossed → F5 alert | Limit watcher + template | ≤ 5s | Cap accidentally exceeded — regulatory risk | CRIT |
| Buyer reply on email → ops first response | Inbound parse + route to ops queue + auto-ack | ≤ 1 business hour | Buyer trust erodes; payment delayed | — |
| Reminder cron (T-3 / T-1 / T+0) | Scheduled email send at 09:00 WAT | ≤ 30s of 09:00 | Reminder lands too early/late; ignored | — |
How we get to these numbers
- Templates pre-rendered. All Meta-approved WhatsApp templates and email templates are pre-cached with placeholders; the only work at send-time is variable substitution.
- Parallel fan-out across channels. S7 (supplier WA) + F4 (financier WA) + B8 (buyer-finance email) are dispatched in parallel from a single
REPAIDevent, never sequentially. Same pattern for S6 + F3 + B6 onFUNDED. - Two channels, one state machine. WhatsApp and email handlers both subscribe to the same domain events. Adding a third channel (SMS, in-app) is additive — never a rewrite.
- OpenAI mini for extraction. Lower latency than alternative vision models on the invoice and waybill passes.
- Webhook-driven, not polled. Wallet events push; we never poll.
- WhatsApp Cloud API + transactional ESP. No on-prem hops. Direct Meta endpoint for WA, verified-domain sender (Postmark / SendGrid) for email with SPF/DKIM/DMARC pre-configured.
Error flows
What the user sees when the rail fails. Each is a real WhatsApp screen, not a vague “something went wrong”.
Action needed · Payment received without reference (likely INV-23)
Recovery, not rejection
An unreferenced payment is a reconciliation problem, not a structural break. The email proposes the most likely match and asks the buyer's finance team to confirm in writing — instead of returning the funds and confusing everyone.
Why this is an email and not a WhatsApp prompt
The buyer's finance team needs a paper trail for any reconciliation adjustment. Email is the audit-grade channel; WhatsApp is not. The financing partner is CC'd on this email too — they know there's an unmatched payment in flight before any close.
Buyer reply → ops triage, not auto-apply
The buyer's "yes" is logged but is not enough alone — an ops user must reconcile in the dashboard. Once applied, the parallel S7 + F4 + B8 fire as for a normal repayment.
Funds held in suspense
Until reconciliation, the unmatched amount sits in a Terracore suspense ledger account, not against any specific invoice. The financier still sees outstanding exposure on INV-23 because it hasn't been closed.
“Funds are safe” is the only sentence that matters
When money flow stalls, the supplier panics. The first three words in the bubble are designed to land that fear immediately.
Three buttons
Switch bank (active), wait (passive), call me (escalate). All three are legitimate; the bot doesn’t push one over the others.
Terracore Financing Bot · UI Flow Architecture · 2026-05-01
WhatsApp visual tokens reflect Meta UI as of Feb 2026. · Back to overview
Tone
Direct, without accusation. The mistake might be benign (wrong invoice resubmitted). The fraud signal is recorded silently and routed to ops; we don’t broadcast suspicion to the supplier.
Money status spelled out
“No money has been disbursed” is a hard line — suppliers panic when a deal stalls.