Zirzir.One API for mobile money.
An open-source, self-hosted payment orchestrator for African mobile money. One REST API in front of Telebirr, Chapa, M-Pesa and more, with a ledger and signed webhooks. Written in Rust, MIT licensed.
- 1 Your app creates a payment
- 2 Zirzir books it
- 3 The provider charges
- 4 The customer confirms
What works today.
Zirzir is an early, self-hosted engine. This is what it does now.
- 01
Native drivers
Telebirr, Chapa, SantimPay, Arifpay and LakiPay, written in Rust over real HTTP. They fail closed on errors.
- 02
Plugins
Bun plugins for M-Pesa (Daraja STK), Airtel Money, Telegram invoices and a CBE Birr USSD helper.
- 03
Double-entry ledger
Integer minor units. Completed payments and split shares are booked atomically and idempotently, in SQLite or a TigerBeetle cluster.
- 04
Signed webhooks
payment.completed, payment.failed and payment.cancelled events, signed with an HMAC and retried after 5m, 15m, 1h and 24h.
- 05
Dashboard and API
A REST API and an embedded dashboard, with bcrypt auth, rate-limited login and idempotency keys.
- 06
Encrypted credentials
Provider credentials are encrypted at rest with AES-256-GCM when you set an encryption key.
- 07
Receipts
HTML receipts, plus a PDF receipt for every payment at /api/v1/payments/:id/receipt.pdf.
Providers.
Nine today. Telebirr and CBE Birr have no status API, so you reconcile those payments in the dashboard.
How it fits together.
Your app talks to one server you run. That server talks to the providers and keeps the books.
Merchant app
TypeScript or Python SDK
Zirzir
Rust server: Axum, SQLite and an embedded dashboard
Ledger
SQLite by default, or a TigerBeetle cluster
Native drivers
Telebirr, Chapa, SantimPay, Arifpay, LakiPay
Bun plugins over stdio JSON-RPC
M-Pesa, Airtel Money, Telegram, CBE Birr USSD
Run it yourself.
Build the dashboard first, then the server. It runs on your own machine or with Docker.
# 1. Build the dashboard
cd server/web
bun install && bun run build
# 2. Build and run the server
cd ..
cargo build --release --locked
export ZIRZIR_ADMIN_API_KEY="$(openssl rand -hex 32)"
./target/release/zirzir-server --port 8080Then open
- Dashboard
- localhost:8080/
- API
- localhost:8080/api/v1
- Health
- localhost:8080/health
Prefer Docker? One command with docker compose runs the same server from server/docker-compose.yml.
For production, also set
- ZIRZIR_PUBLIC_URL
- Your server’s public URL. Providers then call back to Zirzir, and each payment’s callback_url becomes your notification URL.
- ZIRZIR_WEBHOOK_SECRET
- Signs the events sent to your app with X-Zirzir-Signature. No events are sent while it is unset.
- ZIRZIR_ENCRYPTION_KEY
- Encrypts provider credentials at rest. If you lose the key, you re-enter the credentials.
- ZIRZIR_TIGERBEETLE_ADDRESSES
- Optional. Books the ledger in a TigerBeetle cluster instead of SQLite. Switching backends starts empty books.
SDKs and CLI.
Call Zirzir from your backend, or try a charge from the terminal.
TypeScript and Python
- Server mode
- { baseUrl, apiKey }
- Standalone mode, for Chapa, Telebirr and LakiPay
- { provider, credentials }
Flutter and React Native packages are thin checkout wrappers around POST /api/v1/payments. Confirm the final status on your backend.
CLI
zirzir login --server http://localhost:8080
zirzir provider set lakipay \
--public-key "$LAKIPAY_PUBLIC_KEY" \
--secret-key "$LAKIPAY_SECRET_KEY"
zirzir charge --amount 1 --currency ETB \
--provider lakipay
zirzir listen \
--forward-to http://localhost:3000/api/webhooksWhat is not included.
Zirzir is early. This is what it does not do yet, so you can plan around it.
A hosted cloud or an SLA
This is a self-hosted engine, not a multi-tenant cloud. There is no published SLA, and the hosted control plane is not in this repository.
PostgreSQL
SQLite only.
Live FX quotes
Static reference rates. Unknown currencies are rejected.
Filed tax invoices
Receipts are merchant copies, not ERCA or KRA statutory filings.
Plugin worker pools
One Bun process per plugin, with sequential JSON-RPC.
Run payments on your own server.
Docs and source
zirzir.africaQuestions
contact@recitelabs.com