Skip to content

Payroll

Payroll turns contracts, time off and expenses into payslips and salary payments. A pay run calculates gross to net for everyone, an admin approves it, payslips go out, and the money leaves through the payment connection you choose.

Open Payroll, Settings and connections.

  1. Country and rules. Pick Uganda, Kenya, Nigeria or custom rules. The card lists every statutory rate the engine applies and the date they were last checked. With custom rules you enter monthly tax bands and any contributions (rates as fractions, an optional pay cap, and whether they come off before tax).
  2. Currency and pay day. Runs pay in one currency. The pay day is the default payment date; 0 means the last day of the month.
  3. Approval. Optionally require a second admin to approve every run, so nobody can pay out a run they prepared themselves.
  4. Allowances and deductions. Create recurring items such as housing or transport allowance (fixed or a percentage of basic, taxable or not, counting for pension or not) and deductions such as loan repayments (before or after tax).
  5. Payment connections. Connect at least one way to pay. See below.

Then fill in People and pay for everyone: tax ID, social security number, where they are paid (bank, mobile money, Wise or cash) and any allowances. Basic salary comes from the active contract unless you override it. The list shows who is missing payout details.

Country What is calculated
Uganda PAYE with the bands in force from 1 July 2026 (and the earlier bands for older periods), the 10% charge above 10 million, NSSF 5% employee and 10% employer, optional Local Service Tax in July to October
Kenya PAYE bands with 2,400 personal relief, NSSF tiers with the February 2026 limits (and older limits for older periods), SHIF 2.75% with the 300 minimum, Affordable Housing Levy 1.5% each side, NSSF, SHIF and the levy deducted before PAYE, optional NITA levy
Nigeria PAYE under the Nigeria Tax Act 2025 annual bands, pension 8% employee and 10% employer on pensionable pay, rent relief (20% of declared rent, at most 500,000), optional NHF 2.5% of basic
Custom Your monthly tax bands and contributions

Rules are dated, so recalculating an old period uses the rates that applied then. Rates are checked against the tax authorities’ published notices; the date is shown next to them. Confirm them with your accountant before your first live run.

Run payroll asks for a month and calculates everyone with an active contract or a salary on their pay profile:

  • Basic salary is prorated by calendar days for people who start or leave during the month.
  • Approved unpaid leave is deducted at the daily rate over working days.
  • Recurring allowances and deductions are applied.
  • Approved expense claims in the run’s currency are added tax free, once. Claims in another currency are flagged instead.
  • Statutory lines come from the country rules.

Each row opens a full breakdown. Add one-off adjustments (a bonus, a commission, an advance to recover) and the row recalculates. Untick someone to leave them out of this run. Warnings flag missing bank details, tax IDs, negative net pay or a currency mismatch.

Approve locks the run. Payslip PDFs are generated with the workspace branding, year-to-date totals and the account the money goes to (masked). Every employee gets the payslip in the app and the Time Portal, plus a notification, and the run creates the matching payment records.

Choose Pay, pick a connection, and Keanan checks every payslip against it first: who can be paid, the total, and who is blocked and why.

Connection How it pays
Flutterwave Sends a transfer per person to bank accounts or mobile money across Africa. Statuses arrive by webhook.
Paystack Creates a transfer recipient once per person, then a transfer from your Paystack balance. Turn off the transfer OTP in Paystack.
Wise Creates the recipient, a quote and the transfer, then funds it from your Wise balance. Where Wise requires approval in its app, the payout waits there and is picked up once sent.
SEPA bank file Downloads a pain.001.001.03 credit transfer file for any euro area bank, with the salary purpose code. Upload it in online banking.
Bank CSV file Downloads every payment with account details for bulk upload or manual payment.
Your own system Posts the payouts to your HTTPS endpoint as signed JSON. Your system reports results back.

Provider keys are encrypted at rest and never shown again in full. Each payout carries a unique reference, so a retry never pays twice, and a run can only be paid once per person. Failed payouts show the provider’s reason; fix the details and choose Pay again to retry only those.

For file and manual methods, choose Bank confirmed once the bank has executed the transfers, or Mark paid on a single row for cash.

Each connection shows its webhook URL, https://YOUR-WORKSPACE/api/v1/payroll/webhooks/{connection-id}/.

  • Flutterwave: set it under Settings, Webhooks, and use the same secret hash in Keanan.
  • Paystack: set it as the webhook URL; requests are verified with your secret key.
  • Wise: no webhook needed; Keanan checks transfer status every ten minutes and on Refresh statuses.

Keanan sends POST to your endpoint with header X-Keanan-Signature: sha256=<hex HMAC-SHA256 of the body with your secret>:

{
"event": "payroll.payouts.requested",
"run": { "id": "…", "name": "Payroll October 2026", "currency": "KES" },
"payouts": [
{
"reference": "KEA1F2E3D4C5B6A790801",
"payslip_number": "PS-202610-1F2E3D",
"employee": { "id": "…", "email": "ana@acme.com", "name": "Ana Doe" },
"amount": "127076.90",
"currency": "KES",
"destination": { "method": "bank", "bank_code": "068", "account_number": "…" }
}
]
}

Report results to the connection’s webhook URL, signed the same way:

{ "payouts": [ { "reference": "KEA1F2E3D4C5B6A790801", "status": "paid", "provider_reference": "TX-998" } ] }

status is paid or failed (with failure_reason).

Every run has:

  • To pay the authorities: each tax and contribution totalled across the run, employee and employer side, for your returns.
  • Payroll register (CSV): one row per person with every line.
  • Accounting journal (CSV): balanced debits and credits for salaries, employer contributions, net pay payable and each deduction payable.

Platform webhooks can subscribe to payroll.run.approved, payroll.run.paid, payroll.payout.paid and payroll.payout.failed. API keys with the payroll:read scope read the signed-in person’s payslips at /api/v1/payroll/my/payslips/; admin keys with payroll:manage reach the full payroll API under /api/v1/payroll/. The MCP server’s list_my_payslips tool answers questions such as “what was my net pay last month”.

Each employee can download a yearly earnings statement from the app or the Time Portal, totalling salary, reimbursements and referral rewards.