Tabibu records.
Extensions act.
The core server never calls a payment gateway, SMS provider or third-party API directly. Extensions — independently deployed, versioned and restarted — own that responsibility and post results back. Think of it as VS Code: a stable core, and a marketplace of things that plug into it.
Third-party APIs change. Hospital software shouldn't have to redeploy for it.
M-Pesa changes its callback format
Redeploy the entire hospital system, everywhere
Update and redeploy only the M-Pesa extension
One hospital wants Stripe, another wants Pesapal
Fork the codebase or branch on conditionals
Install whichever payment extension each facility needs
An integration crashes
Brings the hospital system down with it
Sidecar fails alone; the ward keeps working, events queue
A new provider launches
A code change in the core, another release cycle
Anyone writes an extension against the published SDK
Three pieces, cleanly separated
Core
Tabibu Server
Owns the clinical record. Publishes events; exposes a narrow /v1/ext/… API. Never calls a third party directly.
Broker
Message queue
Holds events until an extension is ready. If a sidecar crashes, nothing is lost — it redelivers on restart.
Sidecar
Extension runner
A separate container per extension. Reads its manifest, talks to the real M-Pesa, Twilio or lab analyser, and reports back.
Not every integration looks the same
Headless
M-Pesa, SMS, lab analysers, biometric verification
Subscribes to events silently, calls a third-party API, posts the result back. No user opens it directly — most integrations are this shape.
UI-primary
Document export, insurance eligibility checks
The user drives it through an isolated view inside Tabibu. No event subscription — a request comes in, the extension does the work, a result comes back.
Hybrid
Payment status, diagnostics dashboards
Both at once: background processing for the automatic case, plus a view for a clinician or cashier who needs to check or trigger something by hand.
An M-Pesa payment, end to end
- 01
Cashier selects M-Pesa at the billing screen; an invoice is created as pending.
- 02
Tabibu publishes billing.payment_requested — it does not call M-Pesa itself.
- 03
The M-Pesa extension receives the event and calls the Daraja STK Push API.
- 04
The patient enters their PIN; M-Pesa calls the extension's own callback URL, not Tabibu's.
- 05
The extension validates the callback and posts the outcome back to Tabibu's extension API.
- 06
Tabibu records the payment and publishes billing.payment_completed for the till to pick up.
One interface to implement
Extensions are Go binaries built against tabibu-ext-sdk. The SDK handles auth, the message queue connection and graceful shutdown — an author writes three methods.
tabibu extension search mpesa
tabibu extension install mpesa-payments
tabibu extension logs mpesa-payments
tabibu extension reload mpesa-payments
handler.go
type Extension interface {
Name() string
Handle(ctx context.Context, e sdk.Event) error
OnShutdown(ctx context.Context) error
}
func main() {
sdk.Run(&MpesaExtension{})
}An extension registry, for publishing and discovery
A marketplace where facilities install extensions and developers publish new ones — the same model as an editor's extension gallery. The registry, the SDK and the extension API are all being built together; talk to us if you want to build against them early.