CTI Protocol

Protocol Changelog

The versions below indicate the xivo version followed by the protocol version.

Warning

The CTI server protocol is subject to change without any prior warning. If you are using this protocol in your own tools please be sure to check that the protocol did not change before upgrading XiVO

16.11 - 2.2

16.09 - 2.2

16.04 - 2.1

  • the Chitchat command to and from fields are now a list of two strings, xivo_uuid and user_uuid.

16.01 - 2.0

  • the lastconnswins field has been removed from the Login capas command
  • the loginkind field has been removed from the Login capas command
  • the ipbxcommands and regcommands capakinds have been removed from Login capas command
  • the Login password command has been modified. The hashedpassword has been replaced by the password field which is now sent verbatim.

15.20 - 1.2

15.19 - 1.2

  • the Chitchat command to field is now a list of two elements, xivo_uuid and user_id.
  • the getlist command has been removed for the channels listname.
  • many fields have been removed from the getlist command.
    • users list
      • enableclient
      • profileclient
    • phones
      • context
      • protocol
      • simultcalls
      • channels
    • voicemails
      • email
      • fullname
      • old
      • waiting
    • agents
      • phonenumber
  • some ipbxcommands have been removed:
    • mailboxcount
    • atxfer
    • transfer
    • hangup
    • originate

15.18 - 1.2

15.16 - 1.2

15.14 - 1.2

  • the people_purge_personal_contacts message was added.
  • the people_personal_contacts_purged message was added.
  • the people_personal_contact_raw message was added.
  • the people_personal_contact_raw_result message was added.
  • the people_edit_personal_contact message was added.
  • the people_personal_contact_raw_update message was added.
  • the people_import_personal_contacts_csv message was added.
  • the people_import_personal_contacts_csv_result message was added.
  • the people_export_personal_contacts_csv message was added.
  • the people_export_personal_contacts_csv_result message was added.
  • for messages people_personal_contact_deleted and people_favorite_update there are no longer data sub-key.

15.13 - 1.2

  • for channel status update message:
    • the value of commstatus have been changed from linked-caller and linked-called to linked.
    • the key direction have been removed.
    • the key talkingto_kind have been removed.
  • the people_personal_contacts message was added.
  • the people_personal_contacts_result message was added.
  • the people_create_personal_contact message was added.
  • the people_personal_contact_created message was added.
  • the people_delete_personal_contact message was added.
  • the people_personal_contact_deleted message was added.

15.12 - 1.2

  • people_search_result has a new key in relations: source_entry_id
  • the people_favorites message was added.
  • the people_favorites_result message was added.
  • the people_set_favorite message was added.
  • the people_favorite_update message was added.

15.11 - 1.2

  • the fax_progress message was added.

15.09 - 1.2

  • for messages of class history the client cannot request by mode anymore. The server returns all calls and the mode is now metadata for each call.

14.24 - 1.2

  • for messages of class ipbxcommand, the command record and sipnotify have been removed.
  • the logfromclient message has been removed

14.22 - 1.2

  • for messages of class faxsend, the steps file_decoded and file_converted have been removed.

14.06 - 1.2

  • the dial_success message was added

14.05 - 1.2

  • the unhold_switchboard command was renamed resume_switchboard.

13.22 - 1.2

  • the actionfiche message was renamed call_form_result.

13.17 - 1.2

  • for messages of class login_capas from server to client: the key presence has been removed.

13.14 - 1.2

  • for messages of class getlist, list agents and function updatestatus: the key availability in the status object/dictionary has changed values:
    • deleted values: on_call_non_acd_incoming and on_call_non_acd_outgoing
    • added values: * on_call_non_acd_incoming_internal * on_call_non_acd_incoming_external * on_call_non_acd_outgoing_internal * on_call_non_acd_outgoing_external

13.12 - 1.2

  • for messages of class getlist, list agents and function updatestatus: the key availability in the status object/dictionary has changed values:
    • deleted value: on_call_non_acd
    • added values: on_call_non_acd_incoming and on_call_non_acd_outgoing

13.10 - 1.2

  • for messages of class getlist and function updateconfig, the config object/dictionary does not have a rules_order key anymore.

Commands

Objects have the format: “<type>:<xivoid>/<typeid>”

  • <type> can take any of the following values: user, agent, queue, phone, group, meetme, …
  • <xivoid> indicates on which server the object is defined
  • <typeid> is the object id, type dependant
e.g.
user:xivo-test/5 I’m looking for the user that has the ID 5 on the xivo-test server.

Here is a non exaustive list of types:

  • exten
  • user
  • vm_consult
  • voicemail

Agent

Login agent

Client -> Server

{"agentphonenumber": "1000", "class": "ipbxcommand", "command": "agentlogin", "commandid": 733366597}

agentphonenumber is the physical phone set where the agent is going to log on.

Server > Client

  • Login successfull :
{"function": "updateconfig",
 "listname": "queuemembers",
 "tipbxid": "xivo",
 "timenow": 1362664323.94,
 "tid": "Agent/2002,blue",
 "config": {"paused": "0",
            "penalty": "0",
            "membership": "static",
            "status": "1",
            "lastcall": "",
            "interface": "Agent/2002",
            "queue_name": "blue",
            "callstaken": "0"},
 "class": "getlist"}

{"function": "updatestatus",
 "listname": "agents",
 "tipbxid": "xivo",
 "timenow": 1362664323.94,
 "status": {"availability_since": 1362664323.94,
            "queues": [],
            "on_call": false,
            "availability": "available",
            "channel": null},
   "tid": 7,
   "class": "getlist"}
  • The phone number is already used by an other agent :
{"class": "ipbxcommand", "error_string": "agent_login_exten_in_use", "timenow": 1362664158.14}

Logout agent

Client -> Server

{"class": "ipbxcommand", "command": "agentlogout", "commandid": 552759274}

Pause

On all queues

Client -> Server

{"class": "ipbxcommand", "command": "queuepause", "commandid": 859140432, "member": "agent:xivo/1", "queue": "queue:xivo/all"}

Un pause agent

On all queues

Client -> Server

{"class": "ipbxcommand", "command": "queueunpause", "commandid": 822604987, "member": "agent:xivo/1", "queue": "queue:xivo/all"}

Add an agent in a queue

Client -> Server

{"class": "ipbxcommand", "command": "queueadd", "commandid": 542766213, "member": "agent:xivo/3", "queue": "queue:xivo/2"}

Remove an agent from a queue

Client -> Server

{"class": "ipbxcommand", "command": "queueremove", "commandid": 742480296, "member": "agent:xivo/3", "queue": "queue:xivo/2"}

Listen to an agent

Client -> Server

{"class": "ipbxcommand", "command": "listen", "commandid": 1423579492, "destination": "xivo/1", "subcommand": "start"}

Configuration

The following messages are used to retrieve XiVO configuration.

Common fields

  • class : getlist
  • function : listid
  • commandid
  • tipbxid
  • listname : Name of the list to be retreived : users, phones, agents, queues, voicemails, queuemembers
{
   "class": "getlist",
   "commandid": 489035169,
   "function": "listid",
   "tipbxid": "xivo",
   "listname": "........."
}

Users configuration

Return a list of configured user id’s

Client -> Server

{"class": "getlist", "commandid": 489035169, "function": "listid", "listname": "users", "tipbxid": "xivo"}

Server -> Client

{
   "class": "getlist",
   "function": "listid", "listname": "users",
   "list": ["11", "12", "14", "17", "1", "3", "2", "4", "9"],
   "tipbxid": "xivo","timenow": 1362735061.17
   }

User configuration

Return a user configuration

Client -> Server

{
  "class": "getlist",
  "function": "updateconfig",
  "listname": "users",
  "tid": "17",
  "tpbxid": "xivo",  "commandid": 5}

Server -> Client

{
   "class": "getlist",
   "function": "updateconfig",
   "listname": "users",
   "tid": "17",
   "tipbxid": "xivo",
   "timenow": 1362741166.4,
   "config": {
         "enablednd": 0, "destrna": "", "enablerna": 0,  "enableunc": 0, "destunc": "", "destbusy": "", "enablebusy": 0, "enablexfer": 1,
         "firstname": "Alice",  "lastname": "Bouzat", "fullname": "Alice Bouzat",
         "voicemailid": null, "incallfilter": 0,  "enablevoicemail": 0,   "agentid": 2, "linelist": ["7"], "mobilephonenumber": ""}
    }

Phones configuration

Client -> Server

{"class": "getlist", "commandid": 495252308, "function": "listid", "listname": "phones", "tipbxid": "xivo"}

Server > Client

{"class": "getlist", "function": "listid", "list": ["1", "3", "2", "5", "14", "7", "6", "9", "8"],
   "listname": "phones", "timenow": 1364994093.38, "tipbxid": "xivo"}

Individual phone configuration request:

{"class": "getlist", "commandid": 704096693, "function": "updateconfig", "listname": "phones", "tid": "3", "tipbxid": "xivo"}

Server > Client

{"class": "getlist",
   "config": {"allowtransfer": null, "identity": "SIP/ihvbur", "iduserfeatures": 1,
                  "initialized": null, "number": "1000"},
   "function": "updateconfig", "listname": "phones", "tid": "3", "timenow": 1364994093.43, "tipbxid": "xivo"}

Agents configuration

Client -> Server

{"class": "getlist", "commandid": 1431355191, "function": "listid", "listname": "agents", "tipbxid": "xivo"}

Queues configuration

Client -> Server

{"class": "getlist", "commandid": 719950939, "function": "listid", "listname": "queues", "tipbxid": "xivo"}

Server -> Client

{"function": "listid", "listname": "queues", "tipbxid": "xivo",
      "list": ["1", "10", "3", "2", "5", "4", "7", "6", "9", "8"], "timenow": 1382704649.64, "class": "getlist"}

Queue configuration

tid is the id returned in the list field of the getlist response message

Client -> Server

{"commandid":7,"class":"getlist","tid":"3","tipbxid":"xivo","function":"updateconfig","listname":"queues"}

Server -> Client

{
 "function": "updateconfig", "listname": "queues", "tipbxid": "xivo", "timenow": 1382704649.69, "tid": "3",
   "config":
      {"displayname": "red", "name": "red", "context": "default", "number": "3002"},
 "class": "getlist"}

Voicemails configuration

Client -> Server

{"class": "getlist", "commandid": 1034160761, "function": "listid", "listname": "voicemails", "tipbxid": "xivo"}

Queue members configuration

Client -> Server

{"class": "getlist", "commandid": 964899043, "function": "listid", "listname": "queuemembers", "tipbxid": "xivo"}

Server -> Client

{"function": "listid", "listname": "queuemembers", "tipbxid": "xivo",
   "list": ["Agent/2501,blue", "Agent/2500,yellow", "Agent/2002,yellow", "Agent/2003,__switchboard",
            "Agent/2003,blue", "Agent/108,blue", "Agent/2002,blue"],
   "timenow": 1382717016.23,
   "class": "getlist"}

Fax

Send fax

Client -> Server

{"class": "faxsend",
 "filename": "contract.pdf",
 "destination", 41400,
 "size": 100000,
 "data": "<base64 of the fax content>"}

Fax status

Server -> Client

  • pages: number of pages sent (NULL if FAILED)
  • status
    • FAILED: Failed to send fax.
    • PRESENDFAX: Fax number exist and converting pdf->tiff has been done.
    • SUCCESS: Fax sent with success.
{"class": "fax_progress", "status": "SUCCESS", "pages": 2 }

Call control commands

Dial

  • destination can be any number
  • destination can be a pseudo URL of the form “type:ibpx/id”

Client -> Server

{
   "class": "ipbxcommand",
   "command": "dial",
   "commandid": <commandid>,
   "destination": "exten:xivo/<extension>"
}

For example :

{
    "class": "ipbxcommand",
    "command": "dial",
    "commandid": 1683305913,
    "destination": "exten:xivo/1202"
}

The server will answer with either an error or a success:

{
    "class": "ipbxcommand",
    "error_string": "unreachable_extension:1202",
}

{
    "class": "dial_success",
    "exten": "1202"
}

Attended transfer to voicemail

Transfer the current call to a given voicemail and listen to the message before completing the transfer.

Client -> Server

{
    "class": "attended_transfer_voicemail",
    "voicemail": "<voicemail number>"
}

Blind transfer to voicemail

Transfer the current call to a given voicemail.

Client -> Server

{
    "class": "blind_transfer_voicemail",
    "voicemail": "<voicemail number>"
}

Login

Once the network is connected at the socket level, the login process requires three steps. If one of these steps is omitted, the connection is reset by the cti server.

  • login_id, the username is sent as a login to the cti server, cti server answers by giving a sessionid
  • login_pass, the password is sent to the cti server, cti server answers by giving a capaid
  • login_capas, the capaid is returned to the server with the user’s availability, cti server answers with a list of info relevant to the user
{
"commandid": <commandid>,
"class": "login_id",
}
  • class: defined what class of command use.
  • commandid : a unique integer number.

Login ID

Client -> Server

{
"class": "login_id",
"commandid": 1092130023,
"company": "default",
"ident": "X11-LE-24079",
"lastlogout-datetime": "2013-02-19T11:13:36",
"lastlogout-stopper": "disconnect",
"userlogin": <userlogin>,
"xivoversion": "<cti protocol version>"
}

Server -> Client

{
    "class": "login_id",
    "sessionid": "21UaGDfst7",
    "timenow": 1361268824.64,
    "xivoversion": "<cti protocol version>"
}

Note

sessionid is used to calculate the hashed password in next step

Login password

Client -> Server

{
    "class": "login_pass",
    "password": "secret",
    "commandid": <commandid>
}

Server -> Client

{
    "capalist": [
        2
    ],
    "class": "login_pass",
    "replyid": 1646064863,
    "timenow": 1361268824.68
}

If no CTI profile is defined on XiVO for this user, the following message will be sent:

{
    "error_string": "capaid_undefined",
    "class": "login_pass",
    "replyid": 1646064863,
    "timenow": 1361268824.68
}

Note

the first element of the capalist is used in the next step login_capas

Login capas

Client -> Server

{
"capaid": 3,
"commandid": <commandid>,
"state": "available",
"class": "login_capas"
}

Server -> Client

First message, describes all the capabilities of the client, configured at the server level

  • presence : actual presence of the user
  • userid : the user id, can be used as a reference
  • capas
    • userstatus : a list of available statuses
      • status name
      • color
      • selectionnable status from this status
      • default action to be done when this status is selected
      • long name
    • services : list of availble services
    • phonestatus : list of available phonestatuses with default colors and descriptive names
    • capaxlets : List of xlets configured for this profile
    • appliname
{
   "class": "login_capas"
   "presence": "available",
   "userid": "3",
   "ipbxid": "xivo",
   "timenow": 1361440830.99,
   "replyid": 3,
   "capas": {
            "preferences": false,
            "userstatus": {
                        "available": { "color": "#08FD20",
                                       "allowed": ["available", "away", "outtolunch", "donotdisturb", "berightback"],
                                       "actions": {"enablednd": "false"}, "longname": "Disponible"
                                      },
                        "berightback": {  "color": "#FFB545",
                                          "allowed": ["available", "away", "outtolunch", "donotdisturb", "berightback"],
                                          "actions": {"enablednd": "false"}, "longname": "Bient\u00f4t de retour"
                                        },
                        "disconnected": { "color": "#202020",
                                          "actions": {"agentlogoff": ""}, "longname": "D\u00e9connect\u00e9"
                                        },
                       /* a list of other status depends on the cti server configuration */
            },
         "services": ["fwdrna", "fwdbusy", "fwdunc", "enablednd"],
         "phonestatus": {
                           "16": {"color": "#F7FF05", "longname": "En Attente"},
                           "1":  {"color": "#FF032D", "longname": "En ligne OU appelle"},
                           "0":  {"color": "#0DFF25", "longname": "Disponible"},
                           "2":  {"color": "#FF0008", "longname": "Occup\u00e9"},
                           "-1": {"color": "#000000", "longname": "D\u00e9sactiv\u00e9"},
                           "4":  {"color": "#FFFFFF", "longname": "Indisponible"},
                           "-2": {"color": "#030303", "longname": "Inexistant"},
                           "9":  {"color": "#FF0526", "longname": "(En Ligne OU Appelle) ET Sonne"},
                           "8":  {"color": "#1B0AFF", "longname": "Sonne"}
                        }
      },
   "capaxlets": [["identity", "grid"], ["search", "tab"], ["customerinfo", "tab", "1"], ["fax", "tab", "2"], ["dial", "grid", "2"], ["tabber", "grid", "3"], ["history", "tab", "3"], ["remotedirectory", "tab", "4"], ["features", "tab", "5"], ["people", "tab", "6"], ["conference", "tab", "7"]],
   "appliname": "Client",
}

Second message describes the current user configuration

{
   "function": "updateconfig",
   "listname": "users",
   "tipbxid": "xivo",
   "timenow": 1361440830.99,
   "tid": "3",
   "config": {"enablednd": false},
   "class": "getlist"
}

Third message describes the current user status

{
   "function": "updatestatus",
   "listname": "users",
   "status": {"availstate": "available"},
   "tipbxid": "xivo",
   "tid": "3",
   "class": "getlist",
   "timenow": 1361440830.99
}

Others

call_form_result

This message is received when a call form is submitted from a client to the XiVO.

Client -> Server

{
    "class": "call_form_result",
    "commandid": <commandid>,
    "infos": {"buttonname": "saveandclose",
              "variables": {"XIVOFORM_varname1": "value1",
                            "XIVOFORM_varname2": "value2"}}
}

History

  • size : Size of the list to be sent by the server

Client -> Server

{
   "class": "history",
   "commandid": <commandid>
   "size": "8",
   "xuserid": "<xivoid>/<userfeaturesid>",
}

Server > Client

Send back a table of calls :

  • duration in seconds
  • extension: caller/destination extension
  • fullname: caller ID name
  • mode
    • 0 : sent calls
    • 1 : received calls
    • 2 : missed calls
{
   "class": "history",
   "history": [
      {"calldate": "2013-03-29T08:44:35.273998",
       "duration": 30.148765,
       "extension": "*844201",
       "fullname": "Alice Wonderland",
       "mode": 0},
      {"calldate": "2013-03-28T16:56:48.071213",
       "duration": 58.134744,
       "extension": "41400",
       "fullname": "41400"}
       "mode": 1},
   ],
   "replyid": 529422441,
   "timenow": 1364571477.33
}

Chitchat

Client > Server

{
   "class": "chitchat",
   "alias": "Alice",
   "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse venenatis velit nibh, ac condimentum felis rutrum id.",
   "to": [<xivo_uuid>, <user_uuid>],
   "commandid": <commandid>
}

Server > Client

The following message is received by the remote XiVO client

{
    "class": "chitchat",
    "from": [<xivo_uuid>, <user_uuid>],
    "to": [<xivo_uuid>, <user_uuid>]
    "alias": "Alice",
    "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse venenatis velit nibh, ac condimentum felis rutrum id.",
}

Directory

Request directory information, names matching pattern ignore case.

Client -> Server

{
   "class": "directory",
   "commandid": 1079140548,
   "pattern": "pau"
}

Server > Client

{
   "class": "directory",
   "headers": ["Nom", "Num\u00e9ro", "Mobile", "Autre num\u00e9ro", "E-mail", "Fonction", "Site", "Source"],
   "replyid": 1079140548,
   "resultlist": ["Claire Mapaurtal;;+33644558899;31256;cmapaurtal@societe.com;;;",
                  "Paul Salvadier;+33445236988;+33678521430;31406;psalvadier@societe.com;;;"],
   "status": "ok",
   "timenow": 1378798928.26
}

parking

keepalive

availstate

getipbxlist

{
    "class": "getipbxlist",
    "commandid": <commandid>
}

People

Get relations

This command will trigger a Relations message.

Client -> Server

{
    "class": "get_relations"
}

People headers

Client -> Server

{
  "class": "people_headers",
}

Server -> Client

{
  "class": "people_headers_result",
  "column_headers": ["Status", "Name", "Number"],
  "column_types": [null, null, "number"],
}

Relations

This message can currently only be received as a response to the Get relations command.

  • The xivo_uuid is the id of the server
  • The user_id is the id of the current user.
  • The endpoint_id is the id of the line of the current user or null.
  • The agent_id is the id of the agent of the current user or null.

Server -> Client

{
    "class": "relations",
    "data": {"xivo_uuid": <the xivo uuid>,
             "user_id": <the user id>,
             "endpoint_id": <the endpoint id>,
             "agent_id": <the agent id>}
}

Favorites list

Client -> Server

{
  "class": "people_favorites",
}

Server -> Client

{
  "class": "people_favorites_result",
  "column_headers": ["Firstname", "Lastname", "Phone number", "Mobile", "Fax", "Email", "Agent", "Favorites"],
  "column_types": [null, "name", "number_office", "number_mobile", "fax", "email", "relation_agent", "favorite"],
  "results": [
    {
      "column_values": ["Bob", "Marley", "5555555", "5556666", "5553333", "mail@example.com", null, true],
      "relations": {
        "agent_id": null,
        "user_id": null,
        "endpoint_id": null,
        "source_entry_id": "55"
      },
      "source": "my_ldap_directory"
    }, {
      "column_values": ["Charlie", "Boblin", "5555556", "5554444", "5552222", "mail2@example.com", null, true],
      "relations": {
        "agent_id": 12,
        "user_id": 34,
        "endpoint_id": 56,
        "source_entry_id": "34"
      },
      "source": "internal"
    }
  ]
}

Set favorite

Client -> Server

{
  "class": "people_set_favorite",
  "source": "my_ldap_directory"
  "source_entry_id": "55"
  "favorite": true
}

Server -> Client

{
  "class": "people_favorite_update",
  "source": "my_ldap_directory"
  "source_entry_id": "55"
  "favorite": true
}

STARTTLS

The STARTTLS command is used to upgrade a connection to use SSL. Once connected, the server send a starttls offer to the client which can reply with a starttls message including the status field. The server will then send a starttls message back to the client with the same status and start the handshake if the status is true.

Server -> Client

{
    "class": "starttls"
}

Client -> Server -> Client

{
    "class": "starttls",
    "status": true
}

Note

a client which does not reply to the starttls offer will keep it’s unencrypted connection.

Personal contacts list

Client -> Server

{
  "class": "people_personal_contacts"
}

Server -> Client

{
  "class": "people_personal_contacts_result",
  "column_headers": ["Firstname", "Lastname", "Phone number", "Mobile", "Fax", "Email", "Agent", "Favorites", "Personal"],
  "column_types": [null, "name", "number_office", "number_mobile", "fax", "email", "relation_agent", "favorite", "personal"],
  "results": [
    {
      "column_values": ["Bob", "Marley", "5555555", "5556666", "5553333", "mail@example.com", null, false, true],
      "relations": {
        "agent_id": null,
        "user_id": null,
        "endpoint_id": null,
        "source_entry_id": "abcd-12"
      },
      "source": "personal"
    }, {
      "column_values": ["Charlie", "Boblin", "5555556", "5554444", "5552222", "mail2@example.com", null, false, true],
      "relations": {
        "agent_id": null,
        "user_id": null,
        "endpoint_id": null,
        "source_entry_id": "efgh-34"
      },
      "source": "personal"
    }
  ]
}

Personal contact purge

Client -> Server

{
  "class": "people_purge_personal_contacts",
}

Server -> Client

{
  "class": "people_personal_contacts_purged",
}

Personal contact raw

Client -> Server

{
  "class": "people_personal_contact_raw",
  "source": "personal",
  "source_entry_id": "abcd-1234"
}

Server -> Client

{
  "class": "people_personal_contact_raw_result",
  "source": "personal",
  "source_entry_id": "abcd-1234",
  "contact_infos": {
      "firstname": "Bob",
      "lastname": "Wonderland"
      ...
  }
}

Create personal contact

Client -> Server

{
  "class": "people_create_personal_contact",
  "contact_infos": {
      "firstname": "Bob",
      "lastname": "Wonderland",
      ...
  }
}

Server -> Client

{
  "class": "people_personal_contact_created"
}

Delete personal contact

Client -> Server

{
  "class": "people_delete_personal_contact",
  "source": "personal",
  "source_entry_id": "abcd-1234"
}

Server -> Client

{
  "class": "people_personal_contact_deleted",
  "source": "personal",
  "source_entry_id": "abcd-1234"
}

Edit personal contact

Client -> Server

{
  "class": "people_edit_personal_contact",
  "source": "personal",
  "source_entry_id": "abcd-1234",
  "contact_infos": {
      "firstname": "Bob",
      "lastname": "Wonderland",
      ...
  }
}

Server -> Client

{
  "class": "people_personal_contact_raw_update",
  "source": "personal",
  "source_entry_id": "abcd-1234"
}

Import personal contacts

Client -> Server

{
  "class": "people_import_personal_contacts_csv",
  "csv_contacts": "firstname,lastname\r\nBob,the Builder\r\n,Alice,Wonderland\r\n,BobMissingFields\r\n"
}

Server -> Client

{
  "class": "people_import_personal_contacts_csv_result",
  "created_count": 2,
  "failed": [
      {
          "line": 3,
          "errors": [
              "missing fields"
              ]
      }

  ]
}

Export personal contacts

Client -> Server

{
  "class": "people_export_personal_contacts_csv",
}

Server -> Client

{
  "class": "people_export_personal_contacts_csv_result",
  "csv_contacts": "firstname,lastname\r\nBob,the Builder\r\n,Alice,Wonderland\r\n"
}

Service

  • class : featuresput

Call Filtering

  • function : incallfilter
  • value : true, false activate deactivate filtering

Client -> Server

{"class": "featuresput", "commandid": 1326845972, "function": "incallfilter", "value": true}

Server > Client

{
   "class": "getlist",
   "config": {"incallfilter": true},
   "function": "updateconfig",
   "listname": "users",
   "tid": "2",
   "timenow": 1361456398.52, "tipbxid": "xivo"  }

DND

  • function : enablednd
  • value : true, false activate deactivate DND

Client -> Server

{"class": "featuresput", "commandid": 1088978942, "function": "enablednd", "value": true}

Server > Client

{
   "class": "getlist",
   "config": {"enablednd": true},
   "function": "updateconfig",
   "listname": "users",
   "tid": "2",
   "timenow": 1361456614.55, "tipbxid": "xivo"}

Recording

  • function : enablerecording
  • value : true, false

Activate / deactivate recording for a user, extension call recording has to be activated : Services->IPBX->IPBX services->Extension

Client -> Server

{"class": "featuresput", "commandid": 1088978942, "function": "enablerecording", "value": true, "target" : "7" }

Server > Client

{
   "class": "getlist",
   "config": {"enablerecording": true},
   "function": "updateconfig",
   "listname": "users",
   "tid": "7",
   "timenow": 1361456614.55, "tipbxid": "xivo"}

Unconditional Forward

Forward the call at any time, call does not reach the user

  • function : fwd

Client -> Server

{
   "class": "featuresput", "commandid": 2082138822, "function": "fwd",
   "value": {"destunc": "1002", "enableunc": true}
}

Server > Client

{
   "class": "getlist",
   "config": {"destunc": "1002", "enableunc": true},
   "function": "updateconfig",
   "listname": "users",
   "tid": "2",
   "timenow": 1361456777.98, "tipbxid": "xivo"}

Forward On No Answer

Forward the call to another destination if the user does not answer

  • function : fwd

Client -> Server

{
   "class": "featuresput", "commandid": 1705419982, "function": "fwd",
   "value": {"destrna": "1003", "enablerna": true}
   }

Server > Client

{
   "class": "getlist",
   "config": {"destrna": "1003", "enablerna": true},
   "function": "updateconfig",
   "listname": "users",
   "tid": "2",
   "timenow": 1361456966.89, "tipbxid": "xivo" }

Forward On Busy

Forward the call to another destination when the user is busy

  • function : fwd

Client -> Server

{
   "class": "featuresput", "commandid": 568274890, "function": "fwd",
   "value": {"destbusy": "1009", "enablebusy": true}
   }

Server > Client

{
   "class": "getlist",
   "config": {"destbusy": "1009", "enablebusy": true},
   "function": "updateconfig",
   "listname": "users",
   "tid": "2",
   "timenow": 1361457163.77, "tipbxid": "xivo"
   }

Statistics

Subscribe to queues stats

This message can be sent from the client to enable statitics update on queues

Client -> Server

  {"commandid":36,"class":"subscribetoqueuesstats"}

``Server > Client``

Get queues stats

When statistic update is enable by sending message Subscribe to queues stats.

The first element of the message is the queue id

{"stats": {"10": {"Xivo-LoggedAgents": 0}},
   "class": "getqueuesstats", "timenow": 1384509582.88}
{"stats": {"1": {"Xivo-WaitingCalls": 0}},
   "class": "getqueuesstats", "timenow": 1384509582.89}
{"stats": {"1": {"Xivo-TalkingAgents": "0", "Xivo-AvailableAgents": "1", "Xivo-EWT": "6"}},
   "class": "getqueuesstats", "timenow": 1384512350.25}

Status

These messages can also be received without any request as unsolicited messages.

User status

User status is to manage user presence

  • Request user status update

Client -> Server

{"class": "getlist", "commandid": 107712156,
   "function": "updatestatus",
   "listname": "users",
   "tid": "14", "tipbxid": "xivo"}

Server > Client

{"class": "getlist",
   "function": "updatestatus",
   "listname": "users",
   "status": {"availstate": "outtolunch", "connection": "yes"},
         "tid": "1", "timenow": 1364994093.48, "tipbxid": "xivo"}
  • Change User status

Client -> Server

{"availstate": "away",
    "class": "availstate",
    "commandid": 1946092392,
    "ipbxid": "xivo",
        "userid": "1"}

Server > Client

{"class": "getlist",
    "function": "updatestatus",
    "listname": "users",
    "status": {"availstate": "away"},
    "tid": "1", "timenow": 1370523352.6, "tipbxid": "xivo"}

Phone status

Client -> Server

{"class": "getlist", "commandid": 107712156,
   "function": "updatestatus",
   "listname": "phones", "tid": "8", "tipbxid": "xivo"}

Server > Client

{"class": "getlist",
 "function": "updatestatus",
 "listname": "phones",
 "status": {"hintstatus": "0"},
 "tid": "1",
 "timenow": 1364994093.48,
 "tipbxid": "xivo"}

Queue status

Client -> Server

{"commandid":17,"class":"getlist","tid":"8","tipbxid":"xivo","function":"updatestatus","listname":"queues"}

Server > Client

{"function": "updatestatus", "listname": "queues", "tipbxid": "xivo", "timenow": 1382710430.54,
   "status": {"agentmembers": ["1","5"], "phonemembers": ["8"]},
   "tid": "8", "class": "getlist"}

Agent status

  • tid is the agent id.

Client -> Server

{"class": "getlist",
 "commandid": <random_integer>,
 "function": "updatestatus",
 "listname": "agents",
 "tid": "635",
 "tipbxid": "xivo"}

Server > Client

{"class": "getlist",
 "listname": "agents",
 "function": "updatestatus",
 "tipbxid": "xivo",
 "tid": 635,
 "status": {
     "availability": "logged_out",
      "availability_since": 1370868774.74,
      "channel": null,
      "groups": [],
      "on_call_acd": false,
      "on_call_nonacd": false,
      "on_wrapup": false,
      "phonenumber": null,
      "queues": [
          "113"
      ]
  }}
  • availability can take the values:

    • logged_out
    • available
    • unavailable
    • on_call_nonacd_incoming_internal
    • on_call_nonacd_incoming_external
    • on_call_nonacd_outgoing_internal
    • on_call_nonacd_outgoing_external
  • availability_since is the timestamp of the last availability change

  • queues is the list of queue ids from which the agent receives calls

Switchboard

Answer

This allows the switchboard operator to answer an incoming call or unhold a call on-hold.

{"class": "answer", "uniqueid": "12345667.89"}

Unsolicited Messages

These messages are received whenever one of the following corresponding event occurs: sheet message on incoming calls, or updatestatus when a phone status changes.

Sheet

This message is received to display customer information if configured at the server side

{
   "timenow": 1361444639.61,
   "class": "sheet",
   "compressed": true,
   "serial": "xml",
   "payload": "AAADnnicndPBToNAEAbgV1n3XgFN1AP...................",
   "channel": "SIP/e6fhff-00000007"
}

How to decode payload :

>>> b64content = base64.b64decode(<payload content>)
>>> # 4 first cars are the encoded lenght of the xml string (in Big Endian format)
>>> xmllen = struck.unpack('>I',b64content[0:4])
>>> # the rest is a compressed xml string
>>> xmlcontent = zlib.decompress(toto[4:])
>>> print xmlcontent

<?xml version="1.0" encoding="utf-8"?>
   <profile>
      <user>
         <internal name="ipbxid"><![CDATA[xivo]]></internal>
         <internal name="where"><![CDATA[dial]]></internal>
         <internal name="channel"><![CDATA[SIP/barometrix_jyldev-00000009]]></internal>
         <internal name="focus"><![CDATA[no]]></internal>
         <internal name="zip"><![CDATA[1]]></internal>
         <sheet_qtui order="0010" name="qtui" type="None"><![CDATA[]]></sheet_qtui>
         <sheet_info order="0010" name="Nom" type="title"><![CDATA[0230210083]]></sheet_info>
         <sheet_info order="0030" name="Origine" type="text"><![CDATA[extern]]></sheet_info>
         <sheet_info order="0020" name="Num\xc3\xa9ro" type="text"><![CDATA[0230210083]]></sheet_info>
         <systray_info order="0010" name="Nom" type="title"><![CDATA[Maric\xc3\xa9 Sapr\xc3\xaftch\xc3\xa0]]></systray_info>
         <systray_info order="0030" name="Origine" type="body"><![CDATA[extern]]></systray_info>
         <systray_info order="0020" name="Num\xc3\xa9ro" type="body"><![CDATA[0230210083]]></systray_info>
      </user>
   </profile>

The xml file content is defined by the following xsd file: xivo-javactilib/src/main/xsd/sheet.xsd (online version)

Phone status update

Received when a phone status change

  • class : getlist
  • function : updatestatus
  • listname : phones
{
   "class": "getlist",
   "function": "updatestatus",
   "listname": "phones",
   "tipbxid": "xivo",
   "timenow": 1361447017.29,
   .........
}

tid is the the object identification

Example of phone messages received when a phone is ringing :

{.... "status": {"hintstatus": "0"}, "tid": "3"}
{.... "status": {"hintstatus": "8"}, "tid": "3"}

Update notification

Register agent status update

The register_agent_status_update command is used to register to the status updates of a list of agent. Once registered to a agent’s status, the client will receive all Agent status update events for the registered agents.

This command should be sent when an agent is displayed in the people xlet to be able to update the agent status icon.

The Unregister agent status update command should be used to stop receiving updates.

Client -> Server

{
  "class": "register_agent_status_update",
  "agent_ids": [["<xivo-uuid>", "<agent-id1>"],
                ["<xivo-uuid>", "<agent-id2>"],
                ...,
                ["<xivo-uuid>", "<agent-idn>"]],
  "commandid": <commandid>
}

Unregister agent status update

The unregister_agent_status_update command is used to unregister from the status updates of a list of agent.

Once unregistered, the client will stop receiving the Agent status update events for the specified agents.

Client -> Server

{
  "class": "unregister_agent_status_update",
  "agent_ids": [["<xivo-uuid>", "<agent-id1>"],
                ["<xivo-uuid>", "<agent-id2>"],
                ...,
                ["<xivo-uuid>", "<agent-idn>"]],
  "commandid": <commandid>
}

Agent status update

The agent_status_update event is received when the presence of an agent changes.

To receive this event, the user must first register to the event for a specified agent using the Register agent status update command.

To stop receiving this event, the user must send the Unregister agent status update command.

  • data, a dictionary containing 3 fields:
    • agent_id, is an integer containing the ID of the user affected by this status change
    • xivo_uuid: a string containing the UUID of the XiVO that sent the status update
    • status: a string containing the new status, “logged_in” or “logged_out”

Server -> Client

{
  "class": "agent_status_update",
  "data": {
    "agent_id": 42,
    "xivo_uuid": "<the-xivo-uuid>",
    "status": "<status-name>"
  }
}

Register endpoint status update

The register_endpoint_status_update command is used to register to the status updates of a list of lines. Once registered to a endpoint’s status, the client will receive all Endpoint status update events for the registered agents.

This command should be sent when a endpoint is displayed in the people xlet to be able to update the agent status icon.

The Unregister endpoint status update command should be used to stop receiving updates.

Client -> Server

{
  "class": "register_endpoint_status_update",
  "endpoint_ids": [["<xivo-uuid>", "<endpoint-id1>"],
                   ["<xivo-uuid>", "<endpoint-id2>"],
                   ...,
                   ["<xivo-uuid>", "<endpoint-idn>"]],
  "commandid": <commandid>
}

Unregister endpoint status update

The unregister_endpoint_status_update command is used to unregister from the status updates of a list of agent.

Once unregistered, the client will stop receiving the Endpoint status update events for the specified agents.

Client -> Server

{
  "class": "unregister_endpoint_status_update",
  "endpoint_ids": [["<xivo-uuid>", "<endpoint-id1>"],
                   ["<xivo-uuid>", "<endpoint-id2>"],
                   ...,
                   ["<xivo-uuid>", "<endpoint-idn>"]],
  "commandid": <commandid>
}

Endpoint status update

The endpoint_status_update event is received when the status of a line changes.

To receive this event, the user must first register to the event for a specified endpoint using the Register endpoint status update command.

To stop receiving this event, the user must send the Unregister endpoint status update command.

  • data, a dictionary containing 3 fields:
    • endpoint_id, is an integer containing the ID of the line affected by this status change
    • xivo_uuid: a string containing the UUID of the XiVO that sent the status update
    • status: an integer matching an entry in the cti hint configuration

Server -> Client

{
  "class": "endpoint_status_update",
  "data": {
    "endpoint_id": 42,
    "xivo_uuid": "<the-xivo-uuid>",
    "status": <hint-status>
  }
}

Register user status update

The register_user_status_update command is used to register to the status updates of a list of user. Once registered to a user’s status, the client will receive all User status update events for the registered users.

This command should be sent when a user is displayed in the people xlet to be able to update the presence status icon.

The Unregister user status update command should be used to stop receiving updates.

Client -> Server

{
  "class": "register_user_status_update",
  "user_ids": [["<xivo-uuid>", "<user-uuid1>"],
               ["<xivo-uuid>", "<user-uuid2>"],
               ...,
               ["<xivo-uuid>", "<user-uuidn>"]],
  "commandid": <commandid>
}

Unregister user status update

The unregister_user_status_update command is used to unregister from the status updates of a list of user.

Once unregistered, the client will stop receiving the User status update events for the specified users.

Client -> Server

{
  "class": "unregister_user_status_update",
  "user_ids": [["<xivo-uuid>", "<user-uuid1>"],
               ["<xivo-uuid>", "<user-uuid2>"],
               ...,
               ["<xivo-uuid>", "<user-uuidn>"]],
  "commandid": <commandid>
}

User status update

The user_status_update event is received when the presence of a user changes.

To receive this event, the user must first register to the event for a specified user using the Register user status update command.

To stop receiving this event, the user must send the Unregister user status update command.

  • data, a dictionary containing the following fields:
    • user_uuid, a string containing the UUID of the user.
    • user_id, an integer containing the ID of the user.
    • xivo_uuid: a string containing the UUID of the XiVO that sent the status update
    • status: a string containing the new status of the user based on the cti profile configuration

Note

When multiple XiVO share user statuses, the cti profile configuration for presences and phone statuses should match on all XiVO to be displayed properly

Server -> Client

{
  "class": "user_status_update",
  "data": {
    "user_uuid": "<the-user-uuid>",
    "user_id": <the-user-id>,
    "xivo_uuid": "<the-xivo-uuid>",
    "status": "<status-name>"
  }
}

Warning

The user_id field is DEPRECATED and should not be used. Use the user_uuid field instead.

CTI server implementation

In the git repository https://gitlab.com/xivo.solutions/xivo-ctid

  • cti_config handles the configuration coming from the WEBI
  • interfaces/interface_ami, together with asterisk_ami_definitions, amiinterpret and xivo_ami handle the AMI connections (asterisk)
  • interfaces/interface_info handles the CLI-like connections
  • interfaces/interface_webi handles the requests and signals coming from the WEBI
  • interfaces/interface_cti handles the clients’ connections, with the help of client_connection, and it often involves cti_command too
  • innerdata is meant to be the place where all statuses are computed and stored

The main loop uses select() syscall to dispatch the tasks according to miscellaneous incoming requests.

Requirements for innerdata:

  • the properties fetched from the WEBI configuration shall be stored in the relevant xod_config structure
  • the properties fetched from elsewhere shall be stored in the relevant xod_status structure
  • at least two kinds of objects are not “predefined” (as are the phones or the queues, for instance)
    • the channels (in the asterisk SIP/345-0x12345678 meaning)
    • the group and queue members shall be handled in a special way each

The purpose of the ‘relations’ field, in the various structures is to keep track of relations and cross-relations between different objects (a phone logged in as an agent, itself in a queue, itself called by some channels belonging to phones …).

CTI server Message flow

Messages sent from the CTI clients to the server are received by the CTIServer class. The CTIServer then calls interface_cti.CTI class manage_connection method. The interface_cti uses his _cti_command_handler member to parse and run the command. The CTICommandHandler get a list of classes that handle this message from the CTICommandFactory. Then the the interface_cti.CTI calls run_commands on the handler, which returns a list of all commands replies.

To implement a new message in the protocol you have to create a new class that inherits the CTICommand class. Your new class should have a static member caller required_fields which is a list of required fields for this class. Your class should also have a conditions static member which is a list of tupples of conditions to detect that an incoming message matches this class. The __init__ of your class is responsible for the initialization of it’s fields and should call super(<ClassName>, self).__init__(msg). Your class should register itself to the CTICommandFactory.

from xivo_cti.cti.cti_command import CTICommand
from xivo_cti.cti.cti_command_factory import CTICommandFactory

class InviteConfroom(CTICommand):
    required_fields = ['class', 'invitee']
    conditions = [('class', 'invite_confroom')]
    def __init__(self):
        super(InviteConfroom, self).__init__(msg)
        self._invitee = msg['invitee']

CTICommandFactory.register_class(InviteConfroom)

Each CTI commands has a callback list that you can register to from anywhere. Each callback function will be called when this message is received with the command as parameter.

Refer to MeetmeList.__init__ for a callback registration example and to MeetmeList.invite for the implementation of a callback.

from xivo_cti.cti.commands.invite_confroom import InviteConfroom

class MySuperClass(object):
    def __init__(self):
        InviteConfroom.register_callback(self.invite_confroom_handler)

    def invite_confroom_handler(self, invite_confroom_command):
        # Do your stuff here.
        if ok:
            return invite_confroom_command.get_message('Everything is fine')
        else:
            return invite_confroom_command.get_warning('I don't know you, go away', True)

Note

The client’s connection is injected in the command instance before calling callbacks functions. The client’s connection is an interface_cti.CTI instance.