Note: The Python examples below now use requests instead of httplib2. By using requests.post() with the necessary authentication, headers, and SSL options, the code is simpler and compatible with modern Python versions (e.g., 3.11). Successful HTTP 200 responses are parsed with getparser() from xmlrpc.client; otherwise, a ProtocolError is raised. This approach streamlines SSL handling, authentication, and header management.


  * Digest Authentication for Trusted Numbers Manipulation and CLI Mapping

See introduction to XMLAPI for details on Authentication:

https://support.sippysoft.com/a/solutions/articles/106909

#!/usr/bin/env python

## username should be the Web Login of the Customer, password - API password
## 1.2.3.4 should be replaced with target IP/hostname of Sippy

import requests
try:
    from urllib.parse import splituser, splitpasswd
    from xmlrpc.client import ServerProxy, getparser, ProtocolError
except ImportError:
    from urllib import splituser, splitpasswd
    from xmlrpclib import ServerProxy, getparser, ProtocolError

class HTTPSDigestAuthTransport:
    def request(self, host, handler, request_body, verbose=0):
        auth, host = splituser(host)
        username, password = splitpasswd(auth)

        url = "https://" + host + handler
        headers = {'Content-Type': 'text/xml'}

        # Using requests with Digest Authentication equivalent (auth=(username, password))
        resp = requests.post(url, data=request_body, headers=headers, auth=(username, password), verify=True)

        if resp.status_code != 200:
            raise ProtocolError(url, resp.status_code, resp.reason, resp.headers)

        p, u = getparser(0)
        p.feed(resp.content)
        return u.close()

transport = HTTPSDigestAuthTransport()
client = ServerProxy("https://username:[email protected]/xmlapi/xmlapi", transport)

## add a mapping
res = client.addCLIMapping({ 'i_account' : 34, 'cli' : '123456', 'lang' : 'en' })
print(res['result'])

## retrieve list of trusted numbers
res = client.listCLIMappings({ 'i_account' : 34 })
if res['result'] == 'OK':
    for cli, lang in res['list']:
        print(cli, lang)


* Trusted Authentication for Trusted Numbers Manipulation and CLI Mapping

In this example i_customer should be supplied to selected XMLAPI method, which is mandatory for most methods in trusted mode. 


#!/usr/bin/env python
## 1.2.3.4 should be replaced with target IP/hostname of Sippy

import requests
try:
    from xmlrpc.client import ServerProxy, getparser, ProtocolError
except ImportError:
    from xmlrpclib import ServerProxy, getparser, ProtocolError

class HTTPSTrustedAuthTransport:
    def request(self, host, handler, request_body, verbose=0):
        url = "https://" + host + handler
        headers = {'Content-Type': 'text/xml'}

        # Using requests.post() without explicit credentials 
        # (In trusted mode, authentication may differ)
        resp = requests.post(url, data=request_body, headers=headers, verify=True)

        if resp.status_code != 200:
            raise ProtocolError(url, resp.status_code, resp.reason, resp.headers)

        p, u = getparser(0)
        p.feed(resp.content)
        return u.close()

transport = HTTPSTrustedAuthTransport()
client = ServerProxy("https://1.2.3.4/xmlapi/xmlapi", transport)

## add a mapping
res = client.addCLIMapping({ 'i_customer': 1, 'i_account' : 34, 'cli' : '123456', 'lang' : 'en' })
print(res['result'])

## retrieve list of trusted numbers
res = client.listCLIMappings({ 'i_customer': 1, 'i_account' : 34 })
if res['result'] == 'OK':
    for cli, lang in res['list']:
        print(cli, lang)


* Manage Call-Back Calls

#!/usr/bin/env python

import requests
try:
    from urllib.parse import splituser, splitpasswd
    from xmlrpc.client import ServerProxy, getparser, ProtocolError
except ImportError:
    from urllib import splituser, splitpasswd
    from xmlrpclib import ServerProxy, getparser, ProtocolError

my_number = '12061234567'
destination_number = '12067654321'
authname = '000124'

class HTTPSDigestAuthTransport:
    def request(self, host, handler, request_body, verbose=0):
        auth, host = splituser(host)
        username, password = splitpasswd(auth)

        url = "https://" + host + handler
        headers = {'Content-Type': 'text/xml'}

        resp = requests.post(url, data=request_body, headers=headers, auth=(username, password), verify=True)

        if resp.status_code != 200:
            raise ProtocolError(url, resp.status_code, resp.reason, resp.headers)

        p, u = getparser(0)
        p.feed(resp.content)
        return u.close()

transport = HTTPSDigestAuthTransport()
client = ServerProxy("https://username:password@sippy_ip/xmlapi/xmlapi", transport)
res = client.make2WayCallback({
    'authname': authname,
    'cld_first': my_number,
    'cld_second': destination_number,
    'credit_time': 3600 # call should not continue more than an hour
})

if res['result'] == 'OK':
    print(res['i_callback_request'])


* Refunding an Account

#!/usr/bin/env python

import requests
try:
    from urllib.parse import splituser, splitpasswd
    from xmlrpc.client import ServerProxy, getparser, ProtocolError
except ImportError:
    from urllib import splituser, splitpasswd
    from xmlrpclib import ServerProxy, getparser, ProtocolError

class HTTPSDigestAuthTransport:
    def request(self, host, handler, request_body, verbose=0):
        auth, host = splituser(host)
        username, password = splitpasswd(auth)

        url = "https://" + host + handler
        headers = {'Content-Type': 'text/xml'}

        resp = requests.post(url, data=request_body, headers=headers, auth=(username, password), verify=True)

        if resp.status_code != 200:
            raise ProtocolError(url, resp.status_code, resp.reason, resp.headers)

        p, u = getparser(0)
        p.feed(resp.content)
        return u.close()

transport = HTTPSDigestAuthTransport()
client = ServerProxy("https://username:password@sippy_ip/xmlapi/xmlapi", transport)
res = client.accountAddFunds({
    'i_account': 34,
    'amount': 1.23,
    'currency': 'USD',
    'payment_notes': 'Test credit'
})
print(res['result'])

* Python multicall example

https://support.sippysoft.com/a/solutions/articles/3000108533