Pending approvals queue
Pending is a real-time queue of every action awaiting a checker. Branch managers live here during the disbursement window (typically 09:00 to 16:00 Mon-Fri); CFOs check it twice daily for GL and write-offs.

The list view
Default columns: Request ID, Rule, Maker, Amount, Member/Reference, Submitted, Age, State. Colour coding: green for fresh (<10 min), amber for 10-30 min, red for >30 min — these are SLA hints, not blocks.
Filters: My queue (default), All pending, Awaiting OTP, Today, This branch. Group-by: Rule, Maker, Branch.
Opening a request

Click any row to see the request form. It is a read-only view of what the maker submitted plus three blocks:
- Payload — the actual data that will be written if approved (e.g. for LOAN_DISBURSE: member, loan product, amount, disbursement channel, M-Pesa number)
- Context — KYC status, blacklist hits, member's other open loans, savings balance, last 30 days transactions
- Maker note — a free-text justification the maker can write (mandatory for write-offs)
What the checker should verify
A good checker spends 60-90 seconds per request. The minimum checklist:
- Is the member the right person? Compare ID number, phone, photo on file
- Has KYC been verified within the last 12 months?
- Are there any blacklist hits (Metropol, TransUnion, internal)?
- Does the amount match what the maker discussed verbally?
- Is there a duplicate loan in process for the same member?
- Does the disbursement channel (M-Pesa, bank, cash) match the member's preference?
- For write-offs: has the recovery process been exhausted? Is there a board resolution attached?
Approve flow
- Click Approve
- Confirmation modal appears with a one-line summary
- OTP is SMS'd to the checker's registered phone
- Enter OTP within 10 minutes (Resend button after 60 seconds)
- Original action executes in the same transaction — if it fails (e.g. M-Pesa down), the approval is rolled back and the request returns to pending
Reject flow
Click Reject. A modal asks for a reason — minimum 20 characters, mandatory. Common reasons:
The maker is notified by e-mail + in-app and can re-submit with corrections. Rejection does not require OTP — it is logged but lower-risk.
- Amount disputed — needs re-verification with member
- KYC expired — refresh ID copy and re-submit
- Member has another active loan in arrears
- Duplicate submission
- M-Pesa number does not match member record
- Outside business hours (some tenants restrict)
Bulk actions
Tick checkboxes and use the gear-icon Action menu: Bulk approve (each still requires individual OTP — there is no master OTP for safety), Bulk reject with one reason, Re-assign to another checker (CRO only).
Worked scenarios
Scenario — Friday salary day surge
| Character | Role |
|---|---|
| Aisha Hassan | Branch Manager / checker |
| Jane Wambui | Loan Officer 1 |
| Peter Otieno | Loan Officer 2 |
| Kimani Mwangi | Borrower (KES 35,000 salary advance) |
Timeline
- 13:02: Jane submits Kimani's KES 35,000 disbursement (Below KES 50,000 threshold — auto-disbursed, no Pending)
- 13:04: Peter submits Mary Mutua's KES 75,000 advance (Above threshold — Pending DCR-2026-01102)
- 13:05: Aisha opens Pending — sees DCR-01102 plus 8 others (Sorted by age, freshest at top)
- 13:08: Aisha opens DCR-01102, verifies Mary's KYC (refreshed Jan 2026) (Context block shows green KYC badge)
- 13:09: She approves, OTP 392847 sent (SMS arrives in 3s)
- 13:10: Enters OTP (M-Pesa B2C fires KES 75,000 to +254723XXXXXX)
- 13:11: Mary's phone vibrates: "You have received KES 75,000 from MWANANCHI MFI" (Transaction MMBP123XYZ logged)
- 13:11 - 14:25: Aisha clears remaining 38 requests at avg 75s each (All disbursed, zero rejections this batch)
- 14:30: Queue empty (Dashboard shows 0 pending; Aisha returns to floor)
Outcome — 47 disbursements totalling KES 3.8M cleared in 90 minutes. Zero fraud, zero member complaints. Average approval time 78 seconds — within the 2-minute SLA.
Scenario — Catching a wrong M-Pesa number
| Character | Role |
|---|---|
| Jane Wambui | Loan Officer (maker) |
| Aisha Hassan | Branch Manager (checker) |
| Florence Achieng | Borrower receiving KES 120,000 |
Timeline
- 10:14: Jane submits Florence's KES 120,000 disbursement to +254700111222 (Pending DCR-2026-01087)
- 10:17: Aisha opens, checks Context block (Member record shows phone +254722333444 — mismatch)
- 10:18: Aisha clicks Reject with reason: "M-Pesa number on form (+254700111222) does not match member record (+254722333444). Verify with member and resubmit." (Maker notified by e-mail + BridgeERP inbox)
- 10:21: Jane phones Florence, confirms 0722333444 is correct (—)
- 10:22: Re-submits DCR-01092 with corrected number (—)
- 10:23: Aisha approves, OTP, disburses (Funds arrive correct phone)
Outcome — KES 120,000 saved from being lost to a wrong number. Total delay: 9 minutes. The maker received a training note in her file (not a disciplinary — first offence).
Reference
Pending state colour coding
Hints only — no hard block.
| Colour | Age | Meaning |
|---|---|---|
| Green | 0-10 min | Fresh — within SLA |
| Amber | 10-30 min | Approaching SLA breach — checker should prioritise |
| Red | 30+ min | SLA breached — CRO is alerted if escalation is configured |
| Grey | expired | OTP expired without confirmation — back to pending |
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Pending queue is empty but maker insists they submitted | Default My queue filter; the request needs a different checker group. | Switch filter to All pending. Or have the maker check the Audit page for the request ID. |
| Cannot click Approve — button missing | User is not in the checker group for this rule, or is the maker. | Confirm the checker group on the Rules page. Confirm the user UID is different from maker UID. |
| Approve succeeds but no SMS/M-Pesa for the underlying disbursement | M-Pesa provider is in sandbox or down — but the approval was committed. | The system retries via the bridge_mpesa cron. If still failing after 15 min, the loan state will revert to pending_disbursement; investigate Daraja credentials. |
| Request count in Pending doesn't match what I see in the list | Filter is hiding requests outside your branch / authorised users. | Remove all filters except Pending state; numbers should match. |

