Catalog PyPI
PACKAGE EXPLORERView in registry

3cx-xapi-python-sdk

PyPI

Python SDK for the 3CX XAPI (OData v4)

3cxpbxsdkvoipxapi
Versions collected1
Direct dependencies8From release 3.0.0
Last observed20 Oct, 15:29 UTC

README

Version 3.0.0 documentation

3CX Python SDK

A typed Python SDK for the 3CX XAPI (/xapi/v1), built on httpx and Pydantic v2.

Features

  • OAuth2 client-credentials authentication with automatic token refresh
  • OData v4 query builder ($filter, $select, $expand, $orderby, $top, $skip, $count)
  • Automatic pagination — iterate over all pages with a single generator call
  • Full coverage — 37 typed services covering every resource group in the 3CX XAPI swagger spec
  • Auto-generated models — every Pydantic model is generated from swagger.yaml, giving you full IDE autocomplete on every field of every entity (User has 60+ typed fields, Queue has 50+, etc.)
  • Reporting helpers for call log, queue performance, extension statistics, activity log, and more
  • Context-manager support for clean resource management
  • Escape hatches (client.get() / client.post()) for raw access to any endpoint

Installation

pip install 3cx-xapi-python-sdk

Quick start

from threecx import ThreeCXClient, ODataQuery

client = ThreeCXClient(
    base_url="https://pbx.example.com",
    client_id="<service-principal-client-id>",
    client_secret="<service-principal-secret>",
)

# ── Active calls ─────────────────────────────────────────────────────────────
for call in client.active_calls.list():
    print(f"{call.caller} → {call.callee}  ({call.status} since {call.established_at})")

# Drop a specific call
client.active_calls.drop(call_id=42)

# ── Users ─────────────────────────────────────────────────────────────────────
# List first 50 enabled users, sorted by extension number
q = ODataQuery().filter("Enabled eq true").order_by("Number").top(50)
for user in client.users.list(q):
    print(user.number, user.full_name, user.email_address)

# Get a single user and update their e-mail
user = client.users.get(101)
client.users.update(101, {"EmailAddress": "new@example.com"})

# Create a user
from threecx.models import User
new_user = client.users.create(User(
    Number="200",
    FirstName="Alice",
    LastName="Smith",
    EmailAddress="alice@example.com",
))

# ── Queues ────────────────────────────────────────────────────────────────────
for queue in client.queues.list():
    agents = client.queues.get_agents(queue.id)
    print(f"Queue {queue.name}: {len(agents)} agents")

# ── Call history ──────────────────────────────────────────────────────────────
q = ODataQuery().filter("SrcExternal eq true").order_by("SegmentStartTime desc").top(100)
for entry in client.call_history.iterate(q):
    print(entry.segment_start_time, entry.src_caller_number, "→", entry.dst_caller_number, entry.call_answered)

# ── Reports ───────────────────────────────────────────────────────────────────
from datetime import datetime, timedelta, timezone

end = datetime.now(timezone.utc)
start = end - timedelta(days=7)
rows = client.reports.get_call_log(start, end)
print(f"{len(rows)} call-log entries for the last 7 days")

# ── System status ─────────────────────────────────────────────────────────────
status = client.system.get_status()
print(f"PBX {status.version}  calls: {status.calls_active}  disk: {status.disk_usage}%")

# ── Context manager ───────────────────────────────────────────────────────────
with ThreeCXClient(base_url="https://pbx.example.com",
                   client_id="...", client_secret="...") as c:
    print(c.system.get_license())

OData query builder

from threecx import ODataQuery

q = (
    ODataQuery()
    .filter("LastName eq 'Smith'")
    .select("Id", "Number", "FirstName", "LastName", "Email")
    .expand("Groups")
    .order_by("Number")
    .top(25)
    .skip(0)
    .count()
)

All query parameters map directly to OData v4 syntax. Refer to the 3CX XAPI swagger for supported fields per endpoint.

Every method whose endpoint documents query options takes query=, including single-entity and settings getters ($select/$expand), e.g. client.settings.get_mail_settings(query=ODataQuery().select("MailServer")). list() methods return the items of one page; read $count with client.call_history.count(q), or through the escape hatch: client.get("/Users", params=ODataQuery().count().top(0).to_params())["@odata.count"].

Calling actions

3CX actions (POST …/Pbx.Name) take named parameters, and the SDK methods take the same parameters as arguments. Pass the object itself; the method posts it under the parameter name 3CX expects (InstallUpdates wants {"install": {...}}, SetUpdateSettings wants {"settings": {...}}, and so on).

from threecx.models import InstallUpdates, XServiceManageOptions

# Install every available update
available = client.updates.get_updates()
client.updates.install_updates(InstallUpdates(
    key=available["Key"],
    entries=[item["Guid"] for item in available["Entries"]],
))

# Restart a PBX service
client.pbx_services.restart(XServiceManageOptions(service_names=["3CXQueueManager"]))

# A dict with the API's PascalCase keys works wherever a model does
client.pbx_services.stop({"ServiceNames": ["3CXQueueManager"]})

Object arguments accept the model from threecx.models or a plain dict; enum arguments accept the enum or its string value. Actions without parameters take no body argument: client.recordings.archive().

Creating a service principal

  1. Log in to 3CX as admin.
  2. Navigate to Admin → Integrations → API.
  3. Create a new service principal and copy the Client ID and Client Secret.

Services reference

The SDK exposes 37 services as attributes of ThreeCXClient, covering every resource group in swagger.yaml.

Calls & telephony

client.<service>Resource
active_calls/ActiveCalls — list & drop live calls
call_history/CallHistoryView — paginated call log
recordings/Recordings, /RemoteArchivingSettings
voicemail/VoicemailSettings, /MusicOnHoldSettings
fax/Fax, /FaxServerSettings

Users, groups & directories

client.<service>Resource
users/Users — CRUD extensions/users + greetings, phones, provisioning
my_user/MyUser — current authenticated user
groups/Groups — full admin groups (members, rights, restrictions)
my_group/MyGroup — current user's primary group
contacts/Contacts — company phone book
parameters/TenantProperties, /DNProperties, directory info

Call routing & flow

client.<service>Resource
queues/Queues — CRUD call queues & agents
ring_groups/RingGroups — CRUD ring groups
inbound_rules/InboundRules — DID/inbound rules
outbound_rules/OutboundRules — outbound dial rules
receptionists/Receptionists — digital receptionists
holidays/Holidays, /OfficeHours
parkings/Parkings, /CallParkingSettings
call_flow/CallFlowApps, /CallFlowScripts

Trunks & PBX hardware

client.<service>Resource
trunks/Trunks, /TrunkTemplates, /Peers, /Sbcs
phones/PhoneTemplates, /SipDevices, /Fxs, /FxsTemplates, /DeviceInfos, /Firmwares

Communication

client.<service>Resource
chat/ChatHistoryView, /ChatMessagesHistoryView
prompts/PromptSets, /CustomPrompts, /Playlists
email/EmailTemplate

System administration

client.<service>Resource
system/SystemStatus, /LicenseStatus, /Parameters
settings/GeneralSettingsForPbx, /MailSettings, /CDRSettings, ~20 settings domains
pbx_services/Services — start/stop/enable/disable PBX services
backups/Backups, failover & restore settings
updates/GetUpdates(), /InstallUpdates, update settings, prompt set / CRM updates, purge
event_logs/EventLogs
security/SecurityTokens, /ServicePrincipals, /BlackListNumbers, /Blocklist, /AntiHackingSettings, /Firewall
emergency/EmergencyGeoLocations, /EmergencyNotificationsSettings
defs/Defs — codecs, timezones, gateway parameters, countries, DID numbers

Integrations

client.<service>Resource
integrations/Microsoft365Integration, /Microsoft365TeamsIntegration, /GoogleSettings, /AmazonIntegrationSettings, /DataConnectorSettings, /AISettings
crm/CrmIntegration, /CrmTemplates
website_links/WebsiteLinks

Reporting

client.<service>Resource
reports30+ report endpoints: call log, queue & extension statistics, agent login, activity log, SLA breaches, audit, scheduled reports

Escape hatch

Any endpoint not covered by a typed service can be called directly:

data = client.get("/InboundRules", params={"$top": "10"})
client.post("/Backups/Pbx.Backup", json={"description": {"Name": "before-upgrade"}})

client.post() sends json exactly as given, so key an action's body by its parameter names yourself (look them up in swagger.yaml under the action's …RequestBody schema).

Downloads & popularity

Awaiting observations

No metric observations yet

Download counts and popularity will appear here as the collector receives them.

Versions 1

Collected releases
VersionPublishedDirect dependenciesOpen version
3.0.029 Sept 20268

Package advisories

0
No matching advisories collected

This describes our collected data; it is not a security assessment.

Metadata history

Meaningful changes
Current collected state Current

Observed since 20 Oct, 15:29 UTC

No superseded metadata states collected. Unchanged observations do not create new revisions.

Record identity

package:c2427153c5701ee522bd75a20d06a2f701a2abafa698c9dce9f304dbaf8a0912