Bank account verification gate (new — 15 May 2026)
Before a staff member's bank details can be saved, AgroYield checks the account number with the bank itself. On the staff form (/business/hr/staff/new or edit), enter the bank + account number, then click "Verify with bank". We call our payments partner Monnify, which checks NIBSS, and returns the canonical account holder name. The name is then auto-filled into the form (read-only) and a green check appears next to the bank field.
If verification fails, you'll see a small banner: "We couldn't confirm this account at the bank. Please re-check the number or pick a different bank." Save is refused until you verify successfully — operator-typed names are not allowed to reach the disburse rail because a slight mismatch (e.g. "Chijioke Okoli" vs the bank's "Okoli Chijioke E.") causes payouts to fail with a generic error that's hard to debug after the fact.
For staff added before this gate shipped, the existing bank details still work for now — but the next time you edit those fields, you'll be asked to verify before saving.
The HR module includes monthly payroll, leave management, and document tracking. Everything is reachable from the People hub at /business/people via the action cards, or directly via /business/hr/payroll and /business/hr/leave.
Monthly payroll
Generating
At /business/hr/payroll, pick the month and year, then click Generate for {Month YYYY}. The system creates one payroll row per active staff member, pre-filling:
- Gross = the staff member's
gross_monthlyvalue - PAYE, pension, other deductions = 0 (you fill these in)
- Net = computed automatically as
gross - paye - pension - other_deductionsvia a generated column - Status = pending
Generation is idempotent. Re-clicking Generate for the same month doesn't create duplicates — it returns the existing rows.
Rows for staff who were deactivated mid-month
If you generate payroll for a staff member and then deactivate them later in the same month (via the staff register), the payroll entry stays on the books — financial rows are never silently deleted. The row will appear on the payroll page with a small grey Inactive pill next to the staff name, so you know what you're looking at.
When you press Pay via Monnify, the batch will refuse if any pending row belongs to a deactivated staff member. The error names the staff specifically and offers two paths to clear:
- Re-activate the staff record (via the staff register) if the deactivation was a mistake or you still want to pay them this month
- Exclude or Mark paid the row to clean it up — Exclude with reason "Deactivated mid-month" if the staff is genuinely no longer working with you; Mark paid if you settled them outside payroll before deactivating
The numbers in the top counter chip and the bottom TOTAL row always reconcile with what's visible — if you see "3 entries" but only 2 rows, refresh the page (a rare cache edge case). Inactive staff with no entry for the period don't show up — only those whose entry was created while they were still active.
Excluding a row from the batch
Sometimes you don't want a particular staff member paid this month — they may be on unpaid leave, newly-hired and paid manually outside payroll, suspended for the period, or simply pending some verification. To skip a single row from the Pay via Monnify batch without disturbing anyone else:
- On the payroll row, click Exclude.
- Optionally type a reason ("unpaid leave for May", "manual payment", "pending bank verification"). The reason is stored on the row for audit and shows inline as a small italic note.
- The row's status flips to Excluded and the row visually greys out with a strikethrough on the name. The counter chip at the top of the page updates immediately — e.g. "9 of 10 included · ₦450,000 to pay" becomes "8 of 10 included · ₦400,000 to pay".
When you press Pay via Monnify, excluded rows are silently skipped. They stay on the payroll register so you have an audit trail of the decision.
Changed your mind? Click Include on the excluded row to flip it back to Pending. The audit reason stays on the row even after re-including, so a retrospective question like "why was this row paid late despite an exclusion?" is answerable.
Each month is independent — excluding a row in May doesn't carry forward to June. When you click Generate next month, all active staff start as Pending again.
Marking paid
For each row, click Mark paid, then enter:
- Payment date
- Payment method (bank transfer, cash, mobile money, etc.)
- Reference (transaction ID, cheque number, etc.)
The status flips to Paid and the row gets a green chip in both the list and the export.
Excel + PDF export
Each HR page (Payroll, Leave, People, Staff) has an Export menu in the top-right with two options:
- PDF — print-ready, A4 landscape, AgroYield logo + business name + year in the footer. Opens directly to your browser's print dialog.
- Excel —
.xlsxfile with the conventions below.
The Excel export of payroll specifically (payroll-{slug}-YYYY-MM.xlsx) includes:
- A 3-row branded header (business name, period, generated-on date)
- Frozen panes so headers stay visible while scrolling
- Zebra-striped rows for readability
- Status colour chips (green for paid, amber for pending)
- A TOTAL row at the bottom using
=SUM()formulas (not hardcoded values — re-editing rows updates the total) - A4 landscape page setup with footer for printing
Leave, People, and Staff exports follow the same branding conventions, with columns appropriate to each list.
Leave requests
Submitting
At /business/hr/leave, click + New request. Pick the staff member, leave type (Annual, Sick, Maternity, Paternity, Compassionate, Unpaid), start date, end date, and an optional reason.
The system computes days_count server-side from the date range — you don't enter it manually. The leave is created with status Pending.
Approving or rejecting
Each pending request shows Approve and Reject buttons. Approving updates the status and (for paid leave types) adjusts the staff member's leave balance. Rejecting requires an optional reason that's stored with the request.
Balances
Each staff member has an annual leave balance computed from:
- Their
leave_entitlement_days(set on the staff record; default 21) - Minus the sum of
days_countfor approved leave requests this calendar year
The balance shows on the leave list and on each staff member's profile.
Filtering
The leave list filters by status (All / Pending / Approved / Rejected) and by staff member. The status filter is most useful day-to-day — Pending shows you what needs your decision.
Documents
Each staff member has a Documents tab on their detail page. You can upload:
- ID cards (national ID, driver's licence, passport)
- Contracts
- Probation/confirmation letters
- Performance reviews
- Any PDF or image up to 10 MB
Each upload supports an expires_on date (e.g. for ID cards or contracts with renewal dates). Documents within 30 days of expiry get an amber "Expiring soon" chip on the list and contribute to the Expiring documents KPI on the People hub hero.
Downloads use signed URLs with a 5-minute TTL. The file isn't publicly accessible; only the owner and accountants can fetch it.
Tier limits
The HR module is part of the Business Suite. Free-tier accounts can have up to 3 active employees. Pro and Growth tiers have higher caps.
When you hit 75% utilisation (e.g. 3 of 4 on a Pro plan if the cap were 4), you'll see a soft inline prompt encouraging upgrade. At 100%, the + Add staff button is blocked and replaced with a clear upgrade CTA.
Document storage doesn't have a separate cap beyond the 10 MB per file limit. If your business is uploading high volumes, that's a signal to talk to us about an Enterprise plan.
Frequently asked
Why is my staff member missing from the payroll generation?
They need to be is_active = true AND status = 'active'. Staff on leave (status = 'on_leave') are excluded from auto-generation but you can manually add them. Terminated staff (status = 'terminated') are excluded entirely.
Can I generate payroll for a future month? No — the system only generates for the current month or earlier. This prevents accidentally creating placeholder records that become stale.
What if I edit a paid payroll row after the fact? The status stays Paid, and the audit log records the edit. The Excel export reflects the new values on the next download. There's no separate "void and reissue" flow today — direct edit is the path.
Can employees submit their own leave requests? Not currently. Leave is owner/accountant-initiated. The "employee self-service" portal where staff request their own leave is on the roadmap.
What happens to documents when an employee is terminated? They stay attached to the staff record. Statutory documents may need to be retained for years; we don't auto-delete. To remove them you'd manually delete each document from the Documents tab.

