Ronny Nyabuto

Ronny Nyabuto

Software Engineer

Nairobi, Kenya (GMT+3)

Open to new roles · remote, across time zones

01About Me

The first time the internet did anything for me, it wasn't even mine. It was my elder brother's Nokia flip phone, and I had to ask for it.

Class six. I'd punch a song title into Tubidy and wait while that little phone reached across some invisible network and dragged the whole thing back — a track, a Java game, mine now, living in a handset that fit in my palm. Felt like magic. But it cost money. Every download was airtime my brother was counting, megabytes you could feel draining, a small negotiation each time over a thing that was never free and never would be. That's the part that lodged in me before I had words for it: the internet never floated free above the world for me. It showed up already attached to shillings.

By high school I had my own laptop, and the whole relationship flipped. I'd spent years taking things off the internet — music, games, cracked copies of everything. Now I wanted to know how the box worked. Formatted it more times than it deserved, broke it, fixed it, fixed other people's when theirs died. Somewhere in there I stopped being someone the machine performed for and became someone who could make it perform.

What I actually fell for, looking back, was the reaching across — the thing where a phone in your hand asks a question and something far away answers. So I went and studied exactly that. Networks. A CCNA. A telecoms degree. The pipes, the protocols, how the question travels and the answer comes home.

Then it clicked that the most important reaching-across in this whole country wasn't carrying songs anymore. It was carrying money. M-Pesa — a boda guy refreshing his balance twenty times a shift, school fees crossing a network in seconds, a mama mboga's entire day of float riding inside one STK push. Same magic as the Nokia. Except now, there's actual stakes on the line.

I couldn't leave that alone. So I went to live in that layer.

That's me. I build the rails money moves on — the M-Pesa libraries, the eTIMS middleware, the unglamorous plumbing nobody thanks you for until the day it saves them. I measure the things everyone else just assumes are fine. And when I'm not in the code I'm writing — usually about money, or about the distance between the story everyone repeats and the one that's actually true. Which, it turns out, is the same itch I've had since the borrowed Nokia: don't take the magic at face value. Go find out how it really works. Then say so.

02Selected Work

May 2026

Telegram bot for Nairobi commuters — tells you when to leave based on live traffic vs. your personal commute history.

Nairobi traffic isn't bad every day — it's bad on specific routes, at specific hours, in ways Google Maps won't tell you because it doesn't know your commute. Wayward is a Telegram bot that tells you whether to leave now or wait, based on live traffic compared against your own historical baseline for that route, day, and hour. It learns from every trip. Below three data points it stays quiet. Once it has enough signal, it alerts you the moment congestion actually drops — not just when it's theoretically clear. The depart command checks current conditions, forecasts two hours ahead, and sets a watch automatically. scenic scores alternate routes against Overpass data if you'd rather take the long way. NLP handled by Gemini so you can just type where you're going.

Node.js Telegram SQLite Gemini Google Routes
Apr 2026

Python SDK for KRA's eTIMS API — OAuth, VAT arithmetic across five tax bands, idempotency for in-flight failures, and full async support.

KRA's eTIMS API has no official Python SDK. Every developer integrating it rebuilds the same things: OAuth token refresh, VAT arithmetic across five tax bands, idempotency for in-flight network failures — the Schrödinger's Invoice problem where a timeout mid-POST leaves the invoice state unknown. This SDK handles all of that, plus async support with full API parity and a supplier onboarding gateway for informal sector compliance under Finance Act 2023 §16(1)(c). The tax calculator works offline with no credentials. It's the SDK that powers TaxID, the compliance layer I build for the informal economy.

Python KRA eTIMS Async Idempotency
Mar 2026

Flutter package managing the full M-Pesa STK Push lifecycle — from initiation through killed-app recovery, without a proxy server.

Daraja handles STK Push initiation. It doesn't handle what happens when the user locks their phone mid-payment, switches apps, or closes yours entirely before the callback arrives. This Flutter package manages the full payment lifecycle: direct Safaricom API calls without a proxy server, WebSocket delivery of payment status via Appwrite Realtime, automatic state recovery when the app returns from background, and killed-app recovery on next launch via SharedPreferences. Accepts any Kenyan number format — 0712345678, +254712345678, or raw 9-digit — with automatic normalization.

Flutter Dart M-Pesa Appwrite Real-time
Feb 2026

Searchable reference for every Daraja API error code — causes and fixes the official documentation doesn't provide.

Safaricom's Daraja documentation doesn't document its own error codes comprehensively. Developers hit cryptic failures and have nowhere to look. A searchable reference for every error the Daraja API returns — causes, fixes, and context the official docs don't provide. Includes an llms.txt so AI tools can read it correctly. Community-contributed: open a PR to add an error code you've hit.

JavaScript HTML Open Source
Jan 2026

TypeScript library for idempotent M-Pesa STK Push — atomic callback deduplication, polling fallback, and a webhook relay that survives server restarts.

An npm package. Daraja gives you STK Push initiation. It doesn't handle what happens when the callback never arrives, when Safaricom sends the same callback three times under load, when a client retries and gets double-charged, or when your database says SUCCESS and Safaricom has no record of it. This TypeScript library handles all of that: idempotent initiation, atomic callback deduplication, polling fallback, and a reconciliation pass for payments that fall through every other safety net. v0.2.0 adds a webhook relay server — point your Safaricom CallbackURL at the relay and it guarantees delivery to your app with exponential-backoff retries, even if your server restarts mid-payment window.

TypeScript Node.js PostgreSQL M-Pesa Webhooks
Also — client sites
The Mind Doctor Site for a Nairobi psychiatry & wellness practice. Live ↗
Vision Sketch & Build Site for a BORAQS-registered Nairobi architect. Live ↗

03Writing

dev.to
What Daraja 3.0 actually changed for developers — and what it did not
Safaricom's biggest API update since 2019 — what actually changed at the platform level, what stayed the same, and why the core integration challenges are identical to Daraja 2.0.
LinkedIn
KRA eTIMS will reject your invoices because of how Python stores numbers
Why your invoice gets rejected by KRA's validator — a dive into float arithmetic errors, residual drift, and why Decimal is the only safe boundary.
LinkedIn
What eTIMS Integration Actually Requires
VSCU, state isolation, and why most implementations stop at the wrong layer. The infrastructure problem most developers don't hit until it's too late.
dev.to
Safaricom's sandbox STK Query API returns FAILED for successful payments. Here's what's happening.
Why the Daraja STK Query endpoint reports FAILED even when the callback confirms success — and how to build reconciliation logic that handles it.
dev.to
I measured M-Pesa STK Push polling lag on a real device. The variance will ruin your UX.
Same code, same device, same network — 3 seconds one run, 39 the next. A teardown of why fixed polling schedules fail.

04Now

Building TaxID — compliance infrastructure for Kenya's informal economy, live and bootstrapped in the open. Thinking about what it means to build software for systems that were never designed to be programmed against.

Most of the interesting engineering problems in East Africa aren't algorithmic. They're about trust, reliability, and what happens when the network drops.

Based in Nairobi, Kenya (GMT +3). ronnyabuto@gmail.com.