Typed Python library for FreePBX GraphQL API and Asterisk Manager Interface (AMI) — manage extensions, queues, and monitor PBX health.
Project description
pyfreepbx
A typed Python library for Asterisk AMI and experimental FreePBX GraphQL integration.
Status: Alpha (v0.x) — AMI operations use well-documented, stable Asterisk actions and are reliable. GraphQL queries are provisional and need validation against a live FreePBX instance before they can be considered stable.
What Works
| Layer | Stability | Description |
|---|---|---|
| AMI client | Stable | Typed methods for Ping, CoreStatus, PJSIPShowEndpoints, QueueSummary, QueueStatus, QueueAdd, QueueRemove. Escape hatch for arbitrary actions. |
| Health monitoring | Stable | Endpoint registration, queue overview, interface health checks — degrades gracefully without AMI. |
| Queue live ops | Stable | Live stats, member listing, runtime add/remove (changes lost on Asterisk reload). |
| System info | Stable | Asterisk version, uptime, active calls via AMI CoreStatus. |
| Extension read | Experimental | GraphQL queries are unvalidated guesses — will likely need adjustment per instance. |
| Queue config read | Experimental | Queue module GraphQL support is undocumented and may not exist. |
| Extension CRUD | Not implemented | Raises NotSupportedError. FreePBX does not reliably expose write mutations. |
Installation
pip install pyfreepbx
Quick Start
from pyfreepbx import FreePBX
with FreePBX.from_env() as pbx:
# Connect AMI for reliable operational data
if pbx.ami_available:
pbx.connect_ami()
# Queue stats (stable — AMI QueueSummary)
for qs in pbx.queues.stats():
print(f"{qs.queue}: {qs.callers} waiting, {qs.available} available")
# Health overview (stable — AMI PJSIPShowEndpoints)
summary = pbx.health.endpoint_summary()
if summary:
print(f"{summary.registered}/{summary.total} endpoints registered")
# Extension listing (experimental — GraphQL, may need adjustment)
for ext in pbx.extensions.list():
print(f"{ext.extension} {ext.name}")
Or with explicit configuration:
pbx = FreePBX(
host="pbx.example.com",
api_token="your-api-token",
ami_username="admin", # optional — enables live stats
ami_secret="your-secret",
)
Environment Variables
| Variable | Required | Default | Description |
|---|---|---|---|
FREEPBX_HOST |
Yes | — | FreePBX hostname or IP |
FREEPBX_API_TOKEN |
Yes | — | Bearer token for GraphQL API |
FREEPBX_PORT |
No | 443 |
HTTPS port |
FREEPBX_VERIFY_SSL |
No | true |
Verify TLS certificates |
FREEPBX_TIMEOUT |
No | 30 |
HTTP timeout (seconds) |
AMI_HOST |
No | FREEPBX_HOST |
AMI hostname |
AMI_PORT |
No | 5038 |
AMI TCP port |
AMI_USERNAME |
No | — | AMI login username |
AMI_SECRET |
No | — | AMI login secret |
AMI_TIMEOUT |
No | 10 |
AMI socket timeout (seconds) |
Architecture
FreePBX (facade)
├── .extensions → ExtensionService → FreePBXClient (GraphQL) ⚠ experimental
├── .queues → QueueService → FreePBXClient (config, ⚠ experimental) + AMIClient (live, stable)
├── .health → HealthService → FreePBXClient + AMIClient (stable)
└── .system → SystemService → AMIClient (stable)
Design principles:
- AMI for live operational state — this is the reliable backbone
- GraphQL API for configuration/inventory (experimental, instance-dependent)
- Services accept both clients; AMI is always optional
NotSupportedErrorfor operations not confirmed via schema introspection
API Overview
Health (stable)
pbx.health.summary() # → HealthSummary (always works)
pbx.health.pbx_info() # → SystemInfo | None
pbx.health.endpoint_summary() # → EndpointSummary | None
pbx.health.unregistered_endpoints() # → list[Device] | None
pbx.health.queue_overview() # → list[QueueStats] | None
Queues — live operations (stable, AMI)
pbx.queues.stats() # → list[QueueStats]
pbx.queues.members("400") # → list[QueueMember]
pbx.queues.add_member_runtime(...) # AMI QueueAdd (lost on reload)
pbx.queues.remove_member_runtime(...) # AMI QueueRemove (lost on reload)
Queues — config (experimental, GraphQL)
pbx.queues.list() # → list[Queue] ⚠ provisional query
pbx.queues.get("400") # → Queue ⚠ provisional query
System (stable, AMI)
pbx.system.info() # → SystemInfo (AMI CoreStatus)
Extensions (experimental, GraphQL)
pbx.extensions.list() # → list[Extension] ⚠ provisional query
pbx.extensions.get("1001") # → Extension ⚠ provisional query
# create/update/enable/disable → NotSupportedError
Development
git clone https://github.com/dperez/pyfreepbx.git
cd pyfreepbx
pipenv install --dev
pipenv run pytest # run tests
pipenv run pytest --cov=pyfreepbx --cov-report=term-missing # with coverage
pipenv run ruff check src/ tests/ # lint
pipenv run mypy src/ # type check
Known Limitations
- GraphQL queries are provisional — field names, query names, and response structures are educated guesses based on FreePBX 16/17 documentation. Validate via
{ __schema { queryType { fields { name } } } }on your instance. Methods emitUserWarningat runtime. - No extension CRUD —
create,update,enable,disableraiseNotSupportedError. FreePBX does not reliably expose write mutations via the GraphQL API. - Runtime-only queue membership —
add_member_runtime()/remove_member_runtime()changes are lost on Asterisk reload or restart. sip_peers()is deprecated — chan_sip was removed in Asterisk 21. EmitsDeprecationWarning. Will be removed in v0.2.0.- No async support — planned for a future release.
- No ARI or direct DB — intentionally out of scope for v0.1.0.
Contributing
Contributions are welcome. Please open an issue first to discuss what you'd like to change.
See CONTRIBUTING.md for development guidelines.
License
Apache-2.0 — Copyright 2026 Daniel Perez
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pyfreepbx-0.2.0.tar.gz.
File metadata
- Download URL: pyfreepbx-0.2.0.tar.gz
- Upload date:
- Size: 34.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0f2be5e545cf2451edf49f0046f70993bb2532e4c1dc3795e6207909d2c98fa3
|
|
| MD5 |
cb103d997e46ee3b9d6367b6e919889d
|
|
| BLAKE2b-256 |
58e7630d84c09264ea96aed29eb17d76c081dd3388afb9807c9bbe99dc7bd381
|
File details
Details for the file pyfreepbx-0.2.0-py3-none-any.whl.
File metadata
- Download URL: pyfreepbx-0.2.0-py3-none-any.whl
- Upload date:
- Size: 36.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1be85f7068a79efbcc6b9a10240e7721299004857c9c5e7471c2b888390dd465
|
|
| MD5 |
92128cfd462735121462d5fe0ced5ade
|
|
| BLAKE2b-256 |
4418db2a15db60c694bc636ecf61130880e3037ba4a62b43e994a60a4429d700
|