Getting Started with AXL Programming in Python using python-zeep

I’ve seen a lot more folks interested in working on UC automation and custom scripting against CUCM using AXL.  This is great news.  Unfortunately, Python, unlike other languages like Java, has no standard lib support for SOAP.  This means that most samples online end up being one of:

  • DIY with requests
  • Suds (I’m not going to share a link)

Requests is excellent for REST, but as SOAP is a standard, re-inventing the wheel is just plain dumb.  Copypasta of static xml strings is horrible as well.  We want to automate stuff on CallManager – not screw around with xml tags!  We need a library that does the heavy lifting for us.

Suds is not it.  Everyone starts here because the only samples available online use suds.  Suds has not been actively maintained for a number of years.  It has been forked, and the most recent fork is also now not maintained.  And it’s slow.  Very, very slow.

Please use python-zeep.  It is several orders of magnitude faster than suds.  It is under active development.  It abstracts away xml entirely and lets you work with native Python objects.  It supports serialization.  It’s a great piece of software.

So, since its the one thing that all UC engineers want when they get started…  here is a Hello World for a simple add operation to CUCM.  It was tested with Python 3.6.

# -*- coding: utf-8 -*-

from zeep import Client
from zeep.cache import SqliteCache
from zeep.transports import Transport
from zeep.exceptions import Fault
from zeep.plugins import HistoryPlugin
from requests import Session
from requests.auth import HTTPBasicAuth
from urllib3 import disable_warnings
from urllib3.exceptions import InsecureRequestWarning
from lxml import etree


USERNAME = 'axl_magician'
PASSWORD = '99problemsbutsudsaint1'
FQDN = ""
WSDL = 'file://C://path//to//AXLAPI.wsdl'
ADDRESS = "https://{fqdn}:8443/axl/".format(fqdn=FQDN)

def main():
session = Session()
session.verify = False
session.auth = HTTPBasicAuth(USERNAME, PASSWORD)
transport = Transport(cache=SqliteCache(), session=session, timeout=20)
history = HistoryPlugin()
client = Client(wsdl=WSDL, transport=transport, plugins=[history])
axl = client.create_service(BINDING_NAME, ADDRESS)

kwargs = {
"name": "Hello World AAR Group"
except Fault:
for hist in [history.last_sent, history.last_received]:
print(etree.tostring(hist["envelope"], encoding="unicode", pretty_print=True))

if __name__ == '__main__':

I’ve included the xml dump on failures.

Happy coding, and pouring over the AXL API docs!


2 thoughts on “Getting Started with AXL Programming in Python using python-zeep

  1. Hi,

    First of all, thank you for sharing your knowledge.

    I saw a script using suds, do you know what is the command in zeep similar to this one? I’ve tried, client.service.listphone using zeep but there is no “listphone” option.

    result = client.service.listPhone({‘name’:’%SEP%’},{‘name’:”,’description’:”,’model’:”,’protocol’:”})

    Liked by 1 person

  2. Don’t have a setup to run this against now… but in the case here with python-zeep, I’ve created the following service in a variable I call ‘axl’:
    axl = client.create_service(BINDING_NAME, ADDRESS)

    The call for listPhone would then be:
    phone_kwargs = {
    ‘searchCriteria’: {
    ‘returnedTags’: {
    result = axl.listPhone(**phone_kwargs)

    The dict you supplied looks fine at face value. Let me know if you still have trouble and I’ll follow-up with a live api call check…

    See this:


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.