Skip to main content

Typed Python library for FreePBX GraphQL API and Asterisk Manager Interface (AMI) — manage extensions, queues, and monitor PBX health.

Project description

pyfreepbx

CI PyPI version Python versions License Typed

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
  • NotSupportedError for 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 emit UserWarning at runtime.
  • No extension CRUDcreate, update, enable, disable raise NotSupportedError. FreePBX does not reliably expose write mutations via the GraphQL API.
  • Runtime-only queue membershipadd_member_runtime() / remove_member_runtime() changes are lost on Asterisk reload or restart.
  • sip_peers() is deprecated — chan_sip was removed in Asterisk 21. Emits DeprecationWarning. 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pyfreepbx-0.2.0.tar.gz (34.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pyfreepbx-0.2.0-py3-none-any.whl (36.4 kB view details)

Uploaded Python 3

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

Hashes for pyfreepbx-0.2.0.tar.gz
Algorithm Hash digest
SHA256 0f2be5e545cf2451edf49f0046f70993bb2532e4c1dc3795e6207909d2c98fa3
MD5 cb103d997e46ee3b9d6367b6e919889d
BLAKE2b-256 58e7630d84c09264ea96aed29eb17d76c081dd3388afb9807c9bbe99dc7bd381

See more details on using hashes here.

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

Hashes for pyfreepbx-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1be85f7068a79efbcc6b9a10240e7721299004857c9c5e7471c2b888390dd465
MD5 92128cfd462735121462d5fe0ced5ade
BLAKE2b-256 4418db2a15db60c694bc636ecf61130880e3037ba4a62b43e994a60a4429d700

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page