Portal version: 20260523-0001 · Last updated: 2026-05-24
The Super Admin Portal (pbx-admin) is Patiodesk's central control panel. It runs at http://patioweb09:5050 and is used exclusively by Patiodesk operators to manage the entire fleet of deployed PBX instances, handle billing, monitor uptime, and issue licenses.
Clients have their own limited view through the Client Self-Service Portal at /portal.
http://patioweb09:5050Default admin credentials are set via ADMIN_PASSWORD in the .env file at portal startup.
Session stays active for the browser session. Closing the browser logs you out.
The left sidebar groups all features:
| Section | Pages |
|---|---|
| Fleet | Overview, Clients, Provisions, Releases, SLA |
| Licensing | Licenses, Billing |
| Integrations | API Keys, SIP Templates, Webhooks |
| Admin | Audit Log, Users, My MFA, Settings |
URL: /
The main dashboard. Everything here updates live via Server-Sent Events — no manual refresh needed.
| Card | What it shows |
|---|---|
| Total Deployments | All registered PBX instances |
| Online Now | Instances with a heartbeat in the last 10 minutes |
| Fleet Alerts | Clients with critical/warning conditions |
| Active Licenses | Currently valid licenses |
Doughnut chart — visual breakdown of Online / Stale / Offline clients at a glance.
Lists clients that need attention. Click any alert to jump to that client's detail page.
- CRITICAL (red) — offline for over 1 hour, trunk down, or SLA breach
- WARNING (amber) — stale heartbeat (10 min–1 hr), high resource usage
Shows which software versions are running across the fleet. Useful to know how many instances need an upgrade after a release.
Quick count of Active / Expiring / Expired / Revoked licenses.
Last 8 audit events across all admin users.
Real-time active call channels pulled from Asterisk AMI. Refreshes every 30 seconds. Shows channel name, caller ID, duration, and application.
URL: /clients
List of all registered PBX clients. Each row shows: - Client ID, company name, region - Status badge: Online / Stale / Offline - Last heartbeat time - Active license indicator
The client's PBX appliance will auto-register on its first heartbeat if the Client ID matches.
URL: /clients/<client_id>
Tabs across the top:
Raw table of all heartbeat records — timestamp, CPU, memory, disk, active calls, extensions, trunk state.
All alerts ever generated for this client, newest first.
On the client detail page, update any field in the right panel and click Save Changes.
On the client list, use the action menu → Delete. This removes the client and all heartbeat history. Irreversible.
URL: /provisions
Provision records track when and how a PBX appliance was deployed for a client.
Provision records are informational — they don't trigger any automated deployment yet. They serve as an internal record of where each client's PBX lives.
URL: /releases
Track software versions across the fleet.
2.1.0)Releases appear in the Version Distribution panel on the dashboard.
URL: /sla
Daily uptime tracking per client. The system calculates SLA compliance automatically each day at 00:05 UTC.
(actual / expected) × 100Shows each client's: - 30-day average uptime % - SLA target - Number of breaches in the last 30 days - Trend indicator
URL: /sla/<client_id>
30-day daily breakdown table — each row is one day showing: - Heartbeat count (actual vs expected) - Uptime % - Pass / Breach status
Use this page when a client disputes their SLA or when generating a monthly uptime report.
URL: /licenses
Manage license keys issued to clients. Each PBX appliance checks its license on startup.
A license key is shown once — copy it immediately. The key is delivered to the client to activate their PBX appliance.
| State | Meaning |
|---|---|
| Active | Valid, not expired |
| Expiring | Expires within 30 days |
| Expired | Past expiry date — client's PBX may restrict features |
| Revoked | Manually disabled — client's PBX will not start |
On the license detail page, click Revoke. Use this if a client cancels or is suspended.
URL: /billing
Each client has a subscription record linking them to a plan.
To create a subscription: 1. Go to Billing → click New Subscription 2. Select client and plan 3. Set billing cycle (monthly / annual) 4. Set start date 5. Save
Invoices are created manually or auto-generated (if scheduler is configured).
To create an invoice: 1. Click New Invoice 2. Select the subscription 3. Set amount, period, due date 4. Save
Invoice states: Draft → Sent → Paid → Overdue
To mark as paid: Open the invoice → click Mark Paid.
URL: /api-keys
API keys allow external systems (scripts, monitoring tools, Prometheus) to call the portal's API.
read — read-only access to metrics and fleet dataheartbeat — allows sending heartbeatsadmin — full accessCopy the key immediately — it is shown only once.
Pass it in the request header:
X-Api-Key: pd_live_xxxxxxxxxxxxxxxxxxxx
With a read-scoped key, scrape metrics at:
GET /api/v1/metrics
X-Api-Key: <your-key>
URL: /sip-templates
Pre-built SIP provider configurations. When provisioning a new client, apply a template to auto-fill their PBX trunk settings.
| Template | Provider |
|---|---|
| Airtel Private Link | Airtel IMS trunk (private IP, no auth) |
| Twilio Elastic SIP | Twilio SIP trunking |
| Vonage (Nexmo) | Vonage SIP |
| Tata Telebusiness | Tata SIP trunk |
| BSNL SIP | BSNL government SIP |
| Generic SIP | Any standard SIP provider |
Templates are reusable — one template can be applied to multiple clients.
URL: /webhooks
Send real-time event notifications to external URLs when something happens in the portal.
client.offline — client goes offlineclient.online — client comes back onlinesla.breach — SLA breach detectedlicense.expired — license expiryheartbeat.received — every heartbeat (high volume — use carefully){
"event": "client.offline",
"client_id": "acme-corp",
"timestamp": "2026-05-24T14:30:00Z",
"data": { ... }
}
Each webhook has a delivery log — click any webhook → Delivery Log to see past deliveries, response codes, and retry attempts.
URL: /audit
Every action taken by any admin user is logged here. Useful for: - Security reviews - Troubleshooting ("who deleted that client?") - Compliance
Each entry shows: timestamp, actor (user), action, resource type, resource ID, IP address.
Filters: filter by actor, action type, or date range.
URL: /users
Manage admin portal users.
| Role | Can do |
|---|---|
| Super Admin | Everything |
| Viewer | Read-only — can see all data but cannot create, edit, or delete |
Open the user → click Change Password → enter new password → save.
Open the user → toggle Active off → save. The user cannot log in but their audit history is preserved.
URL: /mfa/setup
Set up or reset TOTP-based two-factor authentication for your own account.
Open My MFA → click Disable MFA → confirm with your password.
Once enabled, every login requires the TOTP code after the password.
URL: /settings
System-level configuration for the portal.
| Setting | Description |
|---|---|
| Portal Name | Display name shown in the UI |
| Heartbeat Timeout (online) | Minutes before a client is marked Stale (default: 10) |
| Heartbeat Timeout (stale) | Minutes before a client is marked Offline (default: 60) |
| SLA Default Target | Default uptime % target for new clients (default: 99.5) |
| Alert Email | Email address for system alerts |
URL: /portal/login
A separate login for clients — they see only their own data.
Clients log in with their Client ID and the portal password set by the admin.
On the client detail page → Portal Access section → enter a password → save.
Clients cannot see other clients or any admin settings.
The deployed PBX appliances call this API automatically every 5 minutes. You do not need to call it manually. For reference:
POST /api/heartbeat/<client_id>
X-Heartbeat-Token: <shared-token>
{
"cpu_percent": 23.4,
"memory_percent": 61.2,
"disk_percent": 44.0,
"active_calls": 3,
"extensions_registered": 8,
"extensions_total": 10,
"trunk_state": "Registered",
"sip_errors_count": 0,
"uptime_seconds": 864000
}
The token is set in .env as ADMIN_HEARTBEAT_TOKEN.
cd /home/patio-admin/pbx-admin
bash start.sh
pkill -f "gunicorn.*wsgi:application"
curl -s -o /dev/null -w "%{http_code}" http://localhost:5050/
# 302 = running (redirecting to login)
tail -f /home/patio-admin/pbx-admin/error.log
tail -f /home/patio-admin/pbx-admin/access.log
| Variable | Description |
|---|---|
ADMIN_SECRET_KEY |
Flask session secret — keep private, never share |
ADMIN_PASSWORD |
Initial admin password |
ADMIN_HEARTBEAT_TOKEN |
Shared token for PBX heartbeats |
ADMIN_DEV_MODE |
Set to true for development (disables some security) |
SEED_ADMIN_PASS |
If set, seeds a default admin user on startup |
| Problem | Fix |
|---|---|
| Portal won't start | Check .env has all required vars: ADMIN_SECRET_KEY, ADMIN_PASSWORD, ADMIN_HEARTBEAT_TOKEN |
| Client shows Offline but PBX is running | Check heartbeat token matches on both ends; check network connectivity from PBX to portal |
| SLA data not populating | Scheduler runs at 00:05 UTC — check error.log for APScheduler errors |
| Live Calls shows nothing | AMI secret not configured in app/services/ami_service.py |
| Can't log in | Check ADMIN_PASSWORD in .env; restart gunicorn after any .env change |
| MFA code rejected | Check system clock is synced (timedatectl); TOTP is time-sensitive |