Everything you need to deploy, configure and manage your ISP billing system — from first install to running hundreds of customers.
BroadNet Billing is a complete ISP billing and hotspot management platform built for African internet service providers. It automates M-Pesa and Airtel Money payments, manages PPPoE and hotspot customers, monitors MikroTik routers and generates invoices — all in one dashboard.
Quickstart
Get your billing system live in under 30 minutes. Step-by-step from zero to first customer.
→
Installation
Install on Ubuntu VPS or WSL. Covers Node.js, MySQL, FreeRADIUS and Nginx.
→
Payments
Configure M-Pesa STK push and Airtel Money USSD for automatic payment collection.
→
MikroTik Router
Connect and configure your routers for PPPoE and hotspot via the RouterOS API.
→
Architecture
BroadNet Billing consists of three main components running on your VPS:
cd /var/www
sudo git clone https://github.com/yourrepo/isp-billing.git
cd isp-billing
sudo npm install
sudo cp .env.example .env
sudo nano .env # fill in your DB, M-Pesa, RADIUS values
3
Set up MySQL database
bash
sudo mysql -u root -p
-- In MySQL shell:
CREATE DATABASE isp_billing;
CREATE DATABASE radius;
CREATE USER 'billing'@'localhost' IDENTIFIED BY 'strongpassword';
GRANT ALL ON isp_billing.* TO 'billing'@'localhost';
GRANT ALL ON radius.* TO 'billing'@'localhost';
FLUSH PRIVILEGES;
EXIT;
4
Install FreeRADIUS and run setup script
bash
sudo apt install -y freeradius freeradius-mysql
# Download and run setup script from admin panel:# Settings → FreeRADIUS → Download Setup Script
chmod +x setup-freeradius.sh
sudo bash setup-freeradius.sh
5
Start the app with PM2
bash
sudo npm install -g pm2
pm2 start src/app.js --name isp-billing
pm2 startup && pm2 save # auto-start on reboot
Visit https://billing.yourisp.co.ke to access your admin panel. Log in with the default superadmin credentials set in your .env file, then add your first router.
Need help? If you get stuck at any step, check the Troubleshooting guide or contact support at support@broadnetbilling.co.ke
← Previous
Overview
Next →
Installation
Docs/Features/Payments
Features
Payments
BroadNet Billing supports M-Pesa (Safaricom Daraja) and Airtel Money. Only one provider can be active at a time. When a payment is confirmed, the customer's account is automatically activated or renewed.
M-Pesa (Safaricom Daraja)
Uses the Daraja Lipa Na M-Pesa Online (STK Push) API. The customer receives a payment prompt on their phone and enters their M-Pesa PIN to confirm.
Configuration
Go to Settings → Payments → M-Pesa Settings and fill in:
Production requires HTTPS. Safaricom will only POST callbacks to https:// URLs. Use sandbox for local testing, production only after deploying to your VPS with SSL.
Airtel Money
Uses the Airtel Africa Collection API. The customer receives a USSD prompt and enters their Airtel Money PIN. No STK push — the prompt appears automatically on their phone.
Configuration
Go to Settings → Payments → Airtel Settings:
Field
Where to get it
Client ID
developers.airtel.africa → your app → Key Management
Client Secret
developers.airtel.africa → your app → Key Management
Callback URL
Your domain: https://billing.yourisp.co.ke/api/payments/airtel/callback
Country
KE for Kenya
Currency
KES for Kenya Shillings
Switching providers
In Settings → Payments, click the card for the provider you want to activate. Only one can be active at a time. All new payments will use the active provider immediately — no restart required.
Payment flow
flow
# Admin-initiated (PPPoE customer)
Admin clicks "Collect Payment"
→ POST /api/payments/initiate
→ M-Pesa STK push / Airtel USSD to customer phone
→ Customer enters PIN
→ Safaricom/Airtel POSTs to callback URL
→ Customer activated, invoice generated, SMS sent
# Customer self-service (Hotspot)
Customer connects to WiFi
→ Redirected to hotspot portal
→ Selects package, enters phone
→ Pays via M-Pesa/Airtel
→ Auto-logged into hotspot
← Previous
Packages
Next →
Hotspot Portal
Docs/Setup/MikroTik
Setup guides
MikroTik Router
Connect your MikroTik router to BroadNet Billing via the RouterOS API. The system auto-configures PPPoE, hotspot, RADIUS and firewall rules through a 3-step wizard.
Router wizard — 3 steps
Step 1: Create router record
In Routers → Add Router, enter:
Name — e.g. "Westlands Estate"
Service types — PPPoE, Hotspot, or both
Ethernet ports — ports to add to the billing bridge (e.g. ether2, ether3)
Click Generate Command. Copy the one-line command and paste it into your MikroTik terminal (via Winbox or SSH):
The MikroTik fetches a signed script from your server, creates an API user, and calls back with its IP and credentials. The router record updates automatically — you will see it go from Unprovisioned to Provisioned.
The provisioning token expires in 1 hour. If it expires before the MikroTik runs the command, click Generate Command again to get a fresh token.
Step 3: Configure services
Click Configure Services to start the automated setup. A live log streams each step:
Creates billing-bridge and assigns gateway IP
Adds your ethernet ports to the bridge
Sets up DHCP pool (10.10.10.10 – 10.10.10.254)
Adds RADIUS server pointing to your VPS
Starts PPPoE server on the bridge
Uploads hotspot login page and starts hotspot server
Applies firewall rules
Network defaults
Setting
Default value
Configurable
Bridge name
billing-bridge
No
Bridge gateway
10.10.10.1/24
Yes — .env
DHCP range
10.10.10.10 – 10.10.10.254
Yes — .env
RADIUS timeout
3 seconds
No
CoA port
3799/UDP
No
Requirements
RouterOS 6.49+ or 7.x
RouterOS API enabled on port 8728
MikroTik must be able to reach your VPS on ports 80/443 and 3000
← Previous
FreeRADIUS
Next →
VPS Deployment
Docs/Reference/Environment Variables
Reference
Environment Variables
All configuration is done through the .env file at the root of the project. Copy .env.example to .env and fill in your values.
Application
Variable
Required
Default
Description
APP_PORT
optional
3000
Port the Node.js server listens on
APP_ENV
optional
development
Set to production on VPS
APP_NAME
optional
ISP Billing
Used in SMS/email messages
JWT_SECRET
required
—
64-char random hex string for JWT signing
JWT_EXPIRES_IN
optional
7d
Admin session duration
Database
Variable
Required
Description
DB_HOST
required
MySQL host for billing database
DB_NAME
required
Billing database name (e.g. isp_billing)
DB_USER
required
MySQL username
DB_PASSWORD
required
MySQL password
RADIUS_DB_HOST
required
MySQL host for RADIUS database (can be same as DB_HOST)
RADIUS_DB_NAME
required
RADIUS database name (e.g. radius)
RADIUS_DB_USER
required
RADIUS DB username
RADIUS_DB_PASSWORD
required
RADIUS DB password
RADIUS & Provisioning
Variable
Required
Description
RADIUS_IP
required
IP of your FreeRADIUS server. Use 127.0.0.1 if on same VPS.
RADIUS_SHARED_SECRET
required
Must match clients.conf and MikroTik RADIUS config
PROVISION_BASE_URL
required
Public URL of your server, e.g. https://billing.yourisp.co.ke/provision
PROVISION_SECRET
required
JWT secret for signing provisioning tokens
M-Pesa
Variable
Required
Description
MPESA_CONSUMER_KEY
required
From Safaricom Daraja portal
MPESA_CONSUMER_SECRET
required
From Safaricom Daraja portal
MPESA_SHORTCODE
required
Paybill or till number
MPESA_PASSKEY
required
Lipa Na M-Pesa passkey from Daraja
MPESA_CALLBACK_URL
required
Must be public HTTPS URL
MPESA_ENV
optional
sandbox or production
Airtel Money
Variable
Required
Description
AIRTEL_CLIENT_ID
required
From Airtel Developer Portal
AIRTEL_CLIENT_SECRET
required
From Airtel Developer Portal
AIRTEL_CALLBACK_URL
required
Public HTTPS URL for payment results
AIRTEL_ENV
optional
sandbox or production
AIRTEL_COUNTRY
optional
KE for Kenya
AIRTEL_CURRENCY
optional
KES for Kenya Shillings
SMS & Email
Variable
Required
Description
SMS_ENABLED
optional
true or false
AT_USERNAME
optional
Africa's Talking username (sandbox for testing)
AT_API_KEY
optional
Africa's Talking API key
AT_SENDER_ID
optional
Branded sender ID (max 11 chars, must be registered)
EMAIL_ENABLED
optional
true or false
EMAIL_HOST
optional
SMTP server host
EMAIL_PORT
optional
SMTP port (587 for TLS)
EMAIL_USER
optional
SMTP username
EMAIL_PASS
optional
SMTP password or app password
← Previous
API Reference
Next →
Troubleshooting
Docs/Reference/Troubleshooting
Reference
Troubleshooting
Common issues and how to resolve them. If you can't find your issue here, check the server logs with pm2 logs isp-billing or contact support.
MikroTik provisioning
Host is unreachable when running provision command
The MikroTik cannot reach your server. Check in order:
Is the server URL correct in PROVISION_BASE_URL? No trailing slash, no extra spaces.
Can the MikroTik reach port 80/443? Test: /tool fetch url="https://billing.yourisp.co.ke/health" output=user
Is your VPS firewall allowing port 80/443? Run sudo ufw status
Is AP isolation enabled on the Wi-Fi the MikroTik is connected to? Disable it on your router.
Provision token expired
Tokens are valid for 1 hour. Click Generate Command again in the admin panel to get a fresh token.
FreeRADIUS
FreeRADIUS fails to start — unknown module rest
bash
sudo rm -f /etc/freeradius/3.0/mods-enabled/rest
sudo service freeradius restart
Too many keys — MySQL error on startup
Sequelize's alter: true has added duplicate indexes. Fix in MySQL:
sql
-- Find duplicate indexes
SELECT TABLE_NAME, INDEX_NAME, COUNT(*)
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'isp_billing'
GROUP BY TABLE_NAME, INDEX_NAME
HAVING COUNT(*) > 1;
-- Drop duplicates (example)
ALTER TABLE Settings DROP INDEX settings_category_key_2;
Then set APP_ENV=production in .env to prevent alter: true running again.
MikroTik: UNKNOWNREPLY !empty error
This is normal — RouterOS returns !empty for commands that succeed but return no data (like set commands). It is handled as a success automatically in the current version. If you see it, update mikrotikService.js to the latest version.
Payments
M-Pesa callback not received
Callback URL must be HTTPS — Safaricom does not call HTTP endpoints in production
URL must be publicly accessible — test with curl https://billing.yourisp.co.ke/api/payments/mpesa/callback from any machine
Check Safaricom Daraja portal for delivery logs
Check your logs: pm2 logs isp-billing | grep "M-Pesa callback"
STK push sent but customer not activated
The callback was not received or payment failed. Check:
Payment record in admin panel — look at status field (pending/completed/failed)
If status is pending after 2 minutes, Safaricom callback failed — check callback URL
If status is failed, customer cancelled or had insufficient funds
Hotspot portal
Portal loads but "network connection error"
The hotspot client cannot reach port 3000. Add it to the walled garden: