In urban Kenya the rent itself moves over M-Pesa, but the reminders still move through a caretaker with a call list. This guide turns the 1st-to-5th rent window into an automated, polite voice flow: a four-rung escalation ladder, a keypad menu ("press 1 to hear the paybill again, press 2 if you've already paid, press 3 to talk to the office"), M-Pesa confirmation pairing so paid tenants are never called again, and cost math that lands under KES 2 per unit per month.
Rent collection in Kenyan agencies follows a rhythm every caretaker knows: an SMS nudge around the 25th of the prior month, the paybill fills up on the 1st, follow-ups run through the 5th, and after the 10th somebody starts knocking on doors. The payment rail is digital — a paybill or till per building, house number as the account reference — but the follow-up layer is still human.
The tooling gap is real. Per the 2023–24 KNBS real estate survey, as cited in 2025 industry commentary, only 47.2% of Kenyan real estate agents use any rent-collection software. The other half reconcile M-Pesa statements by hand and chase arrears by personal phone call — which works at 30 units and collapses at 300. The reminder window is a mass, synchronized, deadline-driven problem: hundreds or thousands of tenants, the same five days, every single month. That shape is exactly what a voice API is for.
SMS alone does not close it. A text gets archived; a ringing phone gets answered, and a keypad menu turns the answer into data — who heard the paybill, who says they've paid, who wants to talk.
There is no statutory reminder regime for ordinary residential arrears in Kenya. The Landlord and Tenant Bill, 2021 — which would introduce rent tribunals and notice rules — is still not law as of mid-2026: it passed the National Assembly in June 2024, the Senate passed it with amendments in April 2025, the National Assembly rejected those amendments in July 2025, and it now sits with a mediation committee. Day-to-day tenancy runs on the older patchwork (the Rent Restriction Act for low-rent residential, the Distress for Rent Act as the hard escalation path), and tenancy agreements almost universally set rent due on the 1st with a grace window to the 5th.
The practical consequence: your reminder practice is your policy. Nobody prescribes when or how you remind, so the agencies that win are the ones whose reminders are consistent, polite, and documented — a cadence tenants can predict, and a paper trail that stands up if a dispute ever escalates.
Four rungs, each one slightly firmer, none of them harsh:
Rung
When
What the call says
Keypad options
Gentle reminder
1st
"Rent for this month is now due. Paybill and account read out once."
1 = repeat paybill, 2 = already paid
Grace-window reminder
5th
Same greeting, adds "due by the fifth", reads the paybill back slowly, twice
1 = repeat paybill, 2 = already paid, 3 = office
Office-offer call
10th
"We haven't matched a payment for your unit. Press 3 to talk to the office."
3 leads the menu; 2 still exits
Arrears call
15th onward
Names the outstanding month, states the next step your tenancy agreement provides, always offers the office
3 = office; unanswered calls queue a human follow-up
Each rung only dials tenants still unmatched in your ledger, so a tenant who pays on the 2nd hears exactly one call all month — and a tenant who presses 2 ("already paid") is flagged for reconciliation instead of being re-dialed.
This flow is softer than a collections campaign on purpose. A defaulted borrower may never meet the lender; your tenants greet the caretaker at the gate every morning, and next year's renewals depend on how this month's reminder felt. Rules that keep the ladder polite:
Never state amounts or arrears on the first two rungs. "Rent for this month is due" is a reminder anyone can overhear; "you owe KES 28,000" is not. Save specifics for the arrears rung, delivered to a confirmed answer.
Call in daylight. There is no statutory calling-hours law for this, so treat business hours as the courtesy standard — late-evening reminder calls burn goodwill you cannot buy back.
One call per rung. If it rings out, let the next rung catch them. Nobody should get three robocalls in a week over rent that is four days late.
Speak both languages. A greeting in Swahili with the menu repeated in English covers the whole building: "Kama umeshalipa, bonyeza mbili. If you have already paid, press 2."
Keep one caller ID. Use the same Sautikit number every month so tenants save it as "Makao Properties" and answer it. Inbound calls to that number are free (as of 2026-06-30, per /pricing), so tenants calling back costs you nothing.
Three pieces: a workspace number whose voice_callback_url points at your handler, a nightly job that dials whoever is still unpaid on rung days, and one webhook handler that serves the whole menu. Routing lives on the number — set it once with PUT /v1/numbers/{id}/routing (see the claim-and-route guide) — and the dial loop is one client.calls.create per tenant:
npm install @sautikit/node@0.2.0
// remind.js — dial every unit still unpaid on a rung dayimport { SautikitClient } from "@sautikit/node";const client = new SautikitClient({ apiKey: process.env.SAUTIKIT_API_KEY });// One-time setup: point the number's voice callback at your handler.// Number routing is not in the SDK — plain fetch.await fetch(`https://api.sautikit.com/v1/numbers/${process.env.NUMBER_ID}/routing`, { method: "PUT", headers: { "Authorization": `Bearer ${process.env.SAUTIKIT_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ voice_callback_url: "https://rent.example.co.ke/voice" }),});const unpaid = await db.tenants.unpaidFor("2026-09");for (const t of unpaid) { await client.calls.create({ from: process.env.FROM_NUMBER, to: [t.msisdn], // Same unit, same month, same rung => a crashed-and-rerun job never double-dials. idempotencyKey: `rent:${t.unitId}:2026-09:day5`, });}
The idempotency key matters more here than in most flows: a reminder that arrives twice in ten minutes reads as harassment, not diligence. Keyed on unit, month, and rung, a re-run of a crashed job replays cached responses instead of placing new calls.
getDigits takes no follow-up URL. When the tenant presses a key, Sautikit POSTs back to the samevoice_callback_url with the Digits field populated, so one handler serves the menu and every branch (the voice actions reference covers the full verb set):
// voice.js — Express handler: menu when no digits, branch when digits arriveimport express from "express";import { sauti } from "@sautikit/node";const app = express();app.use(express.json()); // voice callbacks arrive as JSONapp.post("/voice", async (req, res) => { const digits = req.body.Digits || ""; // Outbound reminder: look the tenant up by the number we dialed. const msisdn = req.body.destinationNumber || req.body.callerNumber; const tenant = await db.tenants.findByPhone(msisdn); if (!digits) { return res.json( sauti .say( "Habari. This is a rent reminder from Makao Properties for " + `${tenant.unitLabel}. Rent for this month is due by the fifth.`, { language: "en-KE" }, ) .getDigits({ timeout: 7, numDigits: 1 }, [ // seconds { say: { text: "To hear the paybill number again, press 1. " + "Kama umeshalipa, bonyeza mbili. If you have already paid, press 2. " + "To talk to the office, press 3.", language: "en-KE", }, }, ]) .say("Asante. Thank you, goodbye.", { language: "en-KE" }) .hangup(), ); } if (digits === "1") { // Read the paybill slowly, digit by digit, twice. const readback = `Paybill: 8 8 1 1 0 0. Account: ${spellOut(tenant.unitLabel)}. ` + `Narudia. Paybill: 8 8 1 1 0 0. Account: ${spellOut(tenant.unitLabel)}. Asante.`; return res.json(sauti.say(readback, { language: "en-KE" }).hangup()); } if (digits === "2") { await db.flags.insert({ unitId: tenant.unitId, kind: "claims_paid" }); return res.json( sauti .say("Asante. We will confirm the payment and stop the reminders.", { language: "en-KE" }) .hangup(), ); } if (digits === "3") { return res.json( sauti.dial({ number: process.env.OFFICE_LINE, callerId: process.env.FROM_NUMBER, timeout: 25, }), ); } // Unrecognised key: exit politely — never loop a confused tenant. return res.json(sauti.say("Asante, goodbye.", { language: "en-KE" }).hangup());});
Two details worth stealing even if you rewrite the rest: the paybill readback is spelled digit by digit and repeated ("Narudia" — "I repeat"), because a tenant standing in a noisy courtyard writes it down on the second pass; and the unrecognised-key branch hangs up politely instead of replaying the menu, because a reminder call has no right to hold anyone hostage. Landlords with older handsets in the tenant mix should also read the DTMF reliability guide before tuning timeouts.
If you would rather a natural-language agent than a keypad — "when can we expect the payment?" answered in Swahili — Sautikit's broadcast campaigns run a published AI agent over a contact list with calling windows, retry policies, and per-tenant template variables. The keypad flow above is where most portfolios should start: it is cheaper, predictable, and tenants understand it instantly.
The ladder is only polite if it stops the moment money lands. Wire your Daraja C2B confirmation callback to your tenant ledger: a payment with account reference A12 marks unit A12 paid, and tonight's dial list simply never includes them. Two refinements close the loop completely:
Confirm by voice. A 20-second outbound call — "Tumepokea KES 32,000 for unit A12, receipt SFR4..." — kills the "did it go through?" anxiety that drives half the office's inbound calls on the 1st. The M-Pesa payment confirmation post builds exactly this.
Reconcile press-2 claims daily. "Already paid" flags with no matching statement entry within 48 hours usually mean a typo'd account number — a warm office call finds the orphaned payment before it becomes next month's dispute.
If you also run SMS or WhatsApp legs alongside the calls, that multi-channel layer is Helloduty, the CX platform Sautikit is part of — keep the voice ladder here and the text nudges there.
Sautikit pricing (as of 2026-06-30): outbound voice at KES 3/min, billed per second after connect — KES 0.05 per second — and KES 100/month ex. VAT (KES 116 incl. VAT) per local Nairobi number. See /pricing for current rates. Unanswered calls never connect, so they cost nothing.
Take an agency managing 800 units, and assume 70% of calls are answered:
Rung 1 (all 800 units, ~25 s each): 560 answered × 25 s × KES 0.05 = KES 700
Rung 2 (30% still unpaid = 240 units, ~45 s with keypresses): 168 answered × 45 s × KES 0.05 = KES 378
Rung 3 (8% = 64 units, ~60 s): 45 answered × 60 s × KES 0.05 = KES 135
Number rental: KES 116
Total: roughly KES 1,329 per month, or about KES 1.66 per unit — less than the airtime a caretaker burns on a single afternoon of manual calls, and it scales linearly: 5,000 units lands around KES 8,300 a month on the same assumptions. The arrears rung stays human; everything before it just stopped consuming a salary.
Because practice governs, documentation is your protection. If an arrears case ever reaches auctioneers under the Distress for Rent Act, "we reminded them politely, on schedule, every month" is a claim you want to prove, not assert.
Call logs are automatic.GET /v1/calls returns every reminder with status, duration, and timestamps; filter by date range and export alongside your rent roll.
Keypress outcomes live in your database. Every press-2 claim and press-3 office transfer is a dated, tenant-initiated record.
Billing is auditable. Wallet statements export as CSV, so the cost of the reminder program is a line item, not a guess.
Recording is optional and regulated. If you record arrears-rung conversations (KES 0.50 per recorded minute, as of 2026-06-30), voice is personal data under the Data Protection Act — notify at the start of the call and see the Kenya voice regulation guide before switching it on.
For month-end reviews, you can skip the dashboard entirely: connect Claude to Sautikit's hosted MCP server and ask for last week's reminder calls, their outcomes, and the wallet spend in one prompt.