Kenyan PAYE looks simple until you actually build it: it is a graduated tax on a taxable pay figure that is itself the result of several statutory deductions applied in a specific order, then reduced by personal relief and any insurance relief. Get the order wrong and every net-pay figure is wrong. This is how I set it up in Acumatica so the monthly run produces the right PAYE, the right statutory deductions, and a P10 you can file on iTax without re-keying.
The Kenyan deduction stack
Before any tax, a Kenyan payslip carries statutory deductions that must be modelled as their own earning/deduction types in Acumatica: NSSF (pension, tiered contributions on pensionable pay), SHIF (the health scheme that replaced NHIF, a percentage of gross), and the Affordable Housing Levy (a percentage of gross, matched by the employer). Some of these reduce taxable pay and some do not, so each one needs to be defined with the correct tax treatment — that flag is what makes the PAYE calculation downstream correct. Model the employer-side portions (NSSF employer match, housing levy employer match, SHIF where applicable) as employer contributions, not employee deductions, so they hit cost accounts rather than net pay.
Taxable pay is gross minus the deductions that are allowable before tax (such as the pension contribution up to the allowed limit), and PAYE is computed on that figure. Then personal relief and any insurance relief reduce the tax itself, not the taxable pay. Mixing "reduces taxable pay" with "reduces tax" is the single most common setup error, and it makes every payslip subtly wrong.
Modelling the graduated PAYE bands
PAYE is graduated: the taxable monthly pay is sliced into bands, each band taxed at its own rate, and the results summed. In Acumatica you express this as a tax bracket / graduated tax table where each row holds a threshold and a rate, applied progressively. Keep the band thresholds and rates as configurable data, not hard-coded logic, because the Finance Act changes them and you want to update a table, not redeploy a customisation. The calculation walks the bands from the lowest up, taxing the portion of taxable pay that falls in each band at that band's rate.
// Progressive PAYE over configured bands, then relief against the tax.
// Bands come from a table (upper limit + rate), sorted ascending.
decimal ComputePaye(decimal taxablePay, IReadOnlyList<PayeBand> bands,
decimal monthlyPersonalRelief)
{
decimal tax = 0m, lower = 0m;
foreach (var b in bands)
{
if (taxablePay <= lower) break;
decimal upper = b.UpperLimit ?? decimal.MaxValue;
decimal slice = Math.Min(taxablePay, upper) - lower;
tax += slice * b.Rate; // e.g. 0.10m, 0.25m, 0.30m ...
lower = upper;
}
// Relief reduces the tax, never the taxable pay. PAYE cannot go below zero.
return Math.Max(0m, tax - monthlyPersonalRelief);
}
Personal relief is a fixed monthly amount subtracted from the computed tax for every resident employee. Insurance relief (where an employee qualifies) is a further reduction of the tax, subject to its own cap. Both belong after the band calculation, and PAYE is floored at zero — relief never produces a negative tax that adds to net pay.
Wiring it up in Acumatica Payroll
In Acumatica's Payroll module, each of these becomes a configured object: earning types for gross components, deduction types for NSSF/SHIF/housing and PAYE, and a tax setup that references the graduated table and the reliefs. Attach the right deductions and benefits to each employee's pay through their pay group and employment records, so the monthly batch picks them up automatically. Map every deduction and employer contribution to the correct GL account up front — PAYE payable, NSSF payable, SHIF payable, housing levy payable — because that mapping is what turns the payroll run into a clean set of liabilities to remit rather than a reconciliation headache.
Running the month
The monthly run calculates gross, applies pre-tax deductions to arrive at taxable pay, runs the graduated PAYE with relief, applies the remaining statutory deductions, and produces net pay plus the employer contributions. Review a handful of payslips across the band boundaries every run — a minimum-wage earner, someone straddling a band threshold, and a high earner — because those are where a mis-set treatment flag shows up first. Only release the batch once the control totals (total gross, total PAYE, total each statutory line) reconcile to expectation.
When the Finance Act changes rates mid-year, you need the old rates for prior periods and the new ones going forward. Store effective dates on the band table so a re-run of an old period uses the rates that applied then, not today's.
Remitting and filing
PAYE and the statutory deductions are remitted to their respective bodies on the statutory deadlines — PAYE to KRA, with the monthly P10 return filed on iTax. Drive the return from the payroll figures: produce the per-employee PAYE detail the P10 expects so the filing is an export, not a spreadsheet rebuild. The statutory deductions (NSSF, SHIF, housing levy) each have their own portal and deadline; keep each one's payable account clean so what you remit ties exactly to what the run computed.
Configuration checklist
| Item | How to model it |
|---|---|
| NSSF | Tiered deduction on pensionable pay; employer match as contribution |
| SHIF | Percentage-of-gross deduction, correct tax treatment |
| Housing Levy | Percentage of gross, employee + employer portions |
| PAYE | Graduated band table (effective-dated), computed on taxable pay |
| Personal / insurance relief | Reduces the tax, after bands, floored at zero |
| GL mapping | Separate payable account per statutory line |
Wrapping up
The whole of Kenyan PAYE in Acumatica comes down to modelling each statutory deduction with the correct tax treatment, computing PAYE progressively over an effective-dated band table, and applying relief against the tax rather than the pay. Keep the rates as data, reconcile control totals every run, and let the P10 fall out of the numbers you already computed. Do that and the monthly run is boring — which for payroll is exactly what you want. If you are standing up Kenyan payroll on Acumatica, reach out or keep reading through the rest of the Acumatica blog.
Independent software engineer in Nairobi specialising in Acumatica customisations, Laravel backends, and tax fiscalisation integrations across East and Southern Africa.