The JSON Reports API
All of QueueMetrics JSON Reports API share a common set of guidelines:
-
All requests must contain a valid QueueMetrics username and password, supplied as HTTP "Basic auth". They will usually require a user holding the key
ROBOT
and may require additional security keys where appropriate. -
Both GET and POST requests are allowed - note that GET requests may have a size limit, while there is basically none for POST.
-
Whenever multiple parameters are allowed, for example when querying for multiple data blocks, the same parameter is repeated multiple times.
-
In case you need to pass the API an associative array (hash), all keys within the hash have a common prefix. E.g. an array like
{ A:1, B:2 }
which common prefix is defined as 'k_' should be passed ask_A=1&k_B=2
. -
All dates are to be written exactly in the format "2000-01-01.00:00:00". Make sure you do not forget the dot between the day and the hour.
-
Any missing parameters are read as if they were blank (and vice versa).
-
The names of the data blocks you need will usually be similar to 'OkDO.AgentsOnQueue'. You can get those easily from QueueMetrics - where you see the Excel/CSV export icon, copy the link in your browser and inspect it - it will contain a parameter like "S.OkDO.AgentsOnQueue.123456789". Just remove the first and last parameters.
-
For QA methods, allowed grader types are: "unknown", "agent", "grader" and "caller".
-
QueueMetrics poses no limits on the size of analyses you may want to run. It is advisable to run large reports at night time or when nobody is accessing the system, as they may take quite a lot of RAM and CPU and this may slow down QueueMetrics for interactive users. As an alternative, you could consider having separate QueueMetrics system for reporting, monitoring and APIs, all sharing a common replicated database. Contact Loway to inquire about possible licensing solutions for multiple servers.
Output format
The result can be obtained with two different output formats:
-
a so-called
classic
format, where the result of all API Reports is a JSON hash made up of blocks, that is an array of rows, each of which is an array of strings. Usually the first row of each block contains the titles for subsequent rows. It is mandatory when reading data to check which column contains the title you are looking for, as different versions of QueueMetrics might report columns in a different order. This works, but it kind-of unnatural to parse. -
a more modern
simple
format, where the JSON is a hash of blocks, each of which is a list of JSON objects where the keys are columns names and values are a string representation of the payload. To set output to Simple, just add the parameterjsonFormat=simple
to any input parameters. -
There is always a block called
result
that specifies whether the operation completed successfully or failed, the time it took to complete and a stack trace of the error (if any).
Example
For example, this is a real-time page showing two agent sessions in classic mode. Note how it contains a result
block
and an actual data block (called RealtimeDO.RtAgentsRaw
), and how the two-line result is prefixed by a line showing titles. In general, you are able to get results containing more than one block.
{ "result" : [ [ "Status", "OK" ], [ "Description", "" ], [ "Time elapsed (ms)", 14 ], [ "QM Version", "beta1" ] ], "RealtimeDO.RtAgentsRaw" : [ [ "ACB_queue", "ACB_agent", "ACB_logon", "ACB_extension", "ACB_onPause", "ACB_curPauseCode", "ACB_curPauseTst", "ACB_pausetime", "ACB_pausesess", "ACB_obPauseList", "ACB_serverId", "ACB_lstCallQueue", "ACB_lstCallCaller", "ACB_lstCallTst", "ACB_lstCallivr", "ACB_lstCallWaitLen", "ACB_lstCallLen", "ACB_freeSincePauOrCallTst", "ACB_inCurrStatusSinceTst" ], [ "300", "agent/101", "1689601183", "", "", "", "0", "", "", "", "", "", "", "", "", "", "", "0", "1689601183" ], [ "300", "agent/102", "1689601176", "", "", "", "0", "", "", "", "", "", "", "", "", "", "", "0", "1689601176" ] ] }
And this is the same information in simple
format - as you can see, it is easier to parse, though actually equivalent.
{ "result" : { "Status" : "OK", "QM Version" : "beta1", "Description" : "", "Time elapsed (ms)" : 12 }, "RealtimeDO.RtAgentsRaw" : [ { "ACB_serverId" : "", "ACB_onPause" : "", "ACB_queue" : "300", "ACB_logon" : "1689601183", "ACB_curPauseCode" : "", "ACB_lstCallQueue" : "", "ACB_lstCallivr" : "", "ACB_agent" : "agent/101", "ACB_freeSincePauOrCallTst" : "0", "ACB_lstCallCaller" : "", "ACB_pausesess" : "", "ACB_lstCallWaitLen" : "", "ACB_curPauseTst" : "0", "ACB_extension" : "", "ACB_obPauseList" : "", "ACB_lstCallTst" : "", "ACB_lstCallLen" : "", "ACB_pausetime" : "", "ACB_inCurrStatusSinceTst" : "1689601183" }, { "ACB_serverId" : "", "ACB_onPause" : "", "ACB_queue" : "300", "ACB_logon" : "1689601176", "ACB_curPauseCode" : "", "ACB_lstCallQueue" : "", "ACB_lstCallivr" : "", "ACB_agent" : "agent/102", "ACB_freeSincePauOrCallTst" : "0", "ACB_lstCallCaller" : "", "ACB_pausesess" : "", "ACB_lstCallWaitLen" : "", "ACB_curPauseTst" : "0", "ACB_extension" : "", "ACB_obPauseList" : "", "ACB_lstCallTst" : "", "ACB_lstCallLen" : "", "ACB_pausetime" : "", "ACB_inCurrStatusSinceTst" : "1689601176" } ] }
Note that if column names are missing or repeated, simple
mode will make sure that they are indexed to
a unique, non-empty string.
Reports
For readability’s sake, all examples given below that use the curl command are written on multiple lines. When testing them on a real system, they must be entered on one single long line instead. You must also encode all parameters properly - see URL-Encoding. |
Obtaining statistics: QmStats
This API call will start up a session in QueueMetrics, check if the user exists and has the privilege to run the report, run the analysis, prepare the required results and return them. At the end of the call, the QueueMetrics session is destroyed so no data is kept for further elaboration.
This means that it’s usually the most efficient thing to do to request all needed response information at once, but it’s wise to limit yourself to the minimum data set you will actually need, as each block takes up CPU and memory space to be marshaled between the native Java format, the intermediate JSON format and the resulting client format.
Method |
QmStats |
Auth required? |
Yes - user must hold the key ROBOT |
XML-RPC method |
QM.stats |
Available since |
14.06 |
See also |
Example
curl --user robot:robot -i -H "Content-Type: application/json" -X GET "http://localhost:8084/queuemetrics/QmStats/jsonStatsApi.do? queues=q1 &from=2000-01-01.00:00:00 &to=2020-01-01.00:00:00 &block=OkDO.RiassAllCalls &block=OkDO.AgentsOnQueue"
Parameters
-
'queues': the set of queues that must be included in the analysis. They must be separated by a "|" symbol if more than one queue is passed. The queue name is the internal Asterisk queue name. (*)
-
'from': the begin of the reporting period, as a date. (*)
-
'to': the end of the reporting period. (*)
-
'filter': the agent filter - an agent’s name, like "Agent/101" that must be the filter for all the relevant activity.
-
'block' the output blocks that have to be exported. To specify multiple blocks, add multiple times. It is advisable to request all blocks you need in a single call, as it is way cheaper for QueueMetrics to compute different blocks on a data set in memory than to recompute it from scratch on a different API call.
-
'query': a dynamic query to be run to filter out calls (since QM 19). See Call Queries
Parameters marked with an asterisk are mandatory. All parameters must be URL-encoded to form a valid URL.
Where do I find data blocks?
A complete list of possible QueueMetrics blocks is maintained in the QueueMetrics User Manual, chapter 6 "Report Details", where each block is described in detail. The QueueMetrics User Manual can be obtained from the QueueMetrics website.
For every possible block there is a name, a description, a "shortcut code" for ease of identification and an API code (usually referred to as an "XML-RPC code" for historical reasons). That is the name of the block that has to be retrieved over JSON. In QueueMetrics 20+, this appears as "block name" when viewing a block’s detail.
For example, if we want to access the "Disconnection Causes" block, we will look it up in the manual until we encounter "UN03 - Disconnection Causes". We see that its XML-RPC code is "KoDO.DiscCauses", so that is the name of the block we’ll be asking for. Block names are case-sensitive, so make sure you are writing it exactly as it appears on the User Manual. |
For a quick reference, data blocks are also listed in Appendix II of this manual at Available blocks for QmStats .
Reading "raw" blocks
While most of the blocks that one can reference from the JSON APIs match the blocks that are visible within the main reports, there are some special data blocks that are designed for machine data consumption.
Those blocks are named raw and contain data that is not formatted, where:
-
times appear as Unix timestamps and not as a date/time
-
agents, pause codes, outcomes, etc. appear undecoded, as they appear on the source log
-
no localizations (numbers, formats) is applied
This makes it easy to process this information (that is typically lists of calls) from third-party software.
Example
To read a list of taken calls, you would run:
curl --user robot:**** -i -H "Content-Type: application/json" -X GET "http://my.queuemetrics-live.com/----/QmStats/jsonStatsApi.do? queues=500 &from=2000-01-01.00:00:00 &to=2022-01-01.00:00:00 &block=DetailsDO.CallsOkRaw"
Apart from the usual data (that matches the one visible in QueueMetrics) you can also see a list of call events, matching the contents of the "call detail" pop-up.
That information is returned in the field CALLOK_events
, containing a string
that in itself encodes a JSON structure, e.g.:
"[ { \"timestamp\" : 1617788374, \"agent\" : \"agent/301\", \"duration\" : 0, \"type\" : \"NOANSWER\", \"descriptionParms\" : \"\", \"aa\" : false, \"endingTimestamp\" : 1617788374, \"eventDuration\" : 0, \"agentCode\" : \"agent/301\", \"description\" : \"evt_ringnoanswer\" }, { \"timestamp\" : 1617788374, \"agent\" : \"agent/307\", \"duration\" : 1, \"type\" : \"NOANSWER\", \"descriptionParms\" : \"\", \"aa\" : false, \"endingTimestamp\" : 1617788375, \"eventDuration\" : 1, \"agentCode\" : \"agent/307\", \"description\" : \"evt_ringnoanswer\" } ]"
Each of those objects is a detailed call event: a variable, a ring attempt, an IVR keypress…. they are all in there.
Live data: QmRealtime
Obtains the real-time status of a system.
This method is very similar to QmStats but it is used to retrieve the real time stats. The same suggestions that are given for QmStats apply.
Please note that there is a difference between results produced by the API realtime calls and the realtime statistics produced through the QueueMetrics GUI when the key realtime.members_only is equal to true. The difference is related to the agents list shown. As the list of queues passed through the API does not point to a specific QueueMetrics queue instance, it’s not possible to correctly tell elementary queues from aggregate queues having the same name. In this situation the agent list will always be computed as the union of all agents associated to all elementary queues composing the macro queue, even if an existing aggregate queue has a different set of agents assigned to it. |
Method |
QmRealtime |
Auth required? |
Yes - user must hold the key ROBOT |
XML-RPC method |
QM.realtime |
Available since |
14.06 |
See also |
Example
curl --user robot:robot -i -H "Content-Type: application/json" -X GET "http://localhost:8084/queuemetrics/QmRealtime/jsonStatsApi.do? queues=q1 &block=RealtimeDO.RtAgentsRaw &block=RealtimeDO.RtCallsRaw"
Parameters
-
'queues': one or more queues, separated by the pipe "|" symbol. (*)
-
'filter': the agent filter - an agent’s name, like "Agent/101" that must be the filter for all the relevant activity.
-
'block' the output blocks that have to be exported. To specify multiple blocks, add multiple times.
Parameters marked with an asterisk are mandatory.
Data blocks: RealtimeDO
Real-time information, as displayed in the main QM real-time page, using system defaults.
Method | Description |
---|---|
RTRiassunto |
An overview table of the queues in use |
RTCallsBeingProc |
Calls being processed in real-time |
RTAgentsLoggedIn |
Agents logged in and paused |
WallRiassunto |
The wallboard top panel |
WallCallsBeingProc |
The wallboard call list |
VisitorCallsProc |
Calls processed |
VisitorTodaysOk |
Calls taken |
VisitorTodaysKo |
Call lost |
RtAgentsRaw |
Raw agent panel |
RtCallsRaw |
Raw calls panel |
When exporting blocks, it is strongly advisable to use the raw data blocks, RtAgentsRaw and RtCallsRaw , as they are easier to parse.
|
For a quick reference, data blocks are aso listed in Appendix II of this manual at Available blocks for QmRealtime .
Accessing audio files: QmFindAudio
This method lets you download audio files and other meta files associated with a call. In order to retrieve the file name QM will invoke the currently configured Pluggable Modules to search within the current recording set. This can be used by third-party software that needs to retrieve audio recordings via HTTP.
Method |
QmFindAudio |
Auth required? |
Yes - user must hold the key ROBOT |
XML-RPC method |
QM.findAudio |
Available since |
14.06 - 16.07 |
See also |
Example
curl --user robot:robot -i -H "Content-Type: application/json" -X GET "http://localhost:8084/queuemetrics/QmFindAudio/jsonStatsApi.do? id=664745.1"
Parameters
-
'id': the call’s UniqueID. (*)
-
'server': mandatory on clustered systems, the server-id.
-
'timestamp': the time-stamp of the call, as number of seconds since the epoch.
-
'agent': the agent code.
-
'queue': the queue.
Parameters marked with an asterisk are mandatory.
If QM is on a clustered setup, the Server parameter must be passed to qualify the Asterisk call-id.
Some PMs may require the Call start, Agent and Queue parameters;
those are used for fuzzy matching of calls, e.g on an external storage. Most PMs that do an exact match by
CallID do not need those parameters. Notably, LocalFilesByDay requires those parameters
to expand the day, year, queue and such placeholders, if you use them to identify the correct
directory name. So, if you can find a call in the GUI but the service returns no matches,
most likely you need to pass those as well.
|
Response
There is only one response block returned, named "AudioFiles", where the caller will retrieve the filename of each recorded file and a URL to actually download the file.
The following fields are returned:
-
The name for the file, or a symbolic name that is meant for human consumption
-
A relative URL to download the file from
-
A security token
The response may include zero or more files; it is possible that multiple recordings are present for the same call, e.g. because they are of different media type or because recordings were started and ended multiple times. |
Downloading audio files
For security reasons, QueueMetrics does not produce hot-links to audio files that can be accessed by unauthenticated clients.
If you want to download audio files, you need to:
-
Search for audio on a specific call
-
Retrieve the URL and the auth token
-
Download the file from the URL that QueueMetrics provides, setting the HTTP client’s "User-Agent" to the access token
Example: you want to retrieve a call which unique-id is "1234.1" that was processed on a clustered server named "aleph" on July 7, 2016.
You start by asking for audio recordings for the call:
curl --user robot:robot -i -H "Content-Type: application/json" -X GET "http://127.0.0.1:8080/queuemetrics/QmFindAudio/jsonStatsApi.do ?id=1234.1&server=aleph×tamp=1467814694"
QueueMetrics returns the following data block, where an audio recording was positively found:
{ "result" : [ [ "Status", "OK" ], [ "Description", "" ], [ "Time elapsed (ms)", 9 ], [ "QM Version", "16.07-1" ] ], "AudioFiles" : [ [ "qm_popup_streamAudio.do?%2Faudio%2aleph%2F2016%2Fcall-1234.1-x.mp3", "call-1234.1-x.mp3", "QM16071-1616625548" ] ] }
In order to retrieve it, we have to download the URL returned, as relative to the QM webapp, passing the auth token that was returned:
curl -v -A "QM16071-1616625548" "http://127.0.0.1:8080/queuemetrics/qm_popup_streamAudio.do ?%2Faudio%2aleph%2F2016%2Fcall-1234.1-x.mp3" > call-1234.1-x.mp3
The auth token returned is only valid for a random time that lasts from a few seconds to a few minutes after it was created. The token changes on every invocation. So you should submit the request immediately after you search for the file. |
Inserting and retrieving call tags: QmInsertTag
This method is used to associate a new tag for a specific recording call file. This method is used to retrieve the list of tags related to a specific call.
By leaving the "message" empty, no new tag will be added but a list of existing tags for a specific calls can be retrieved. |
Method |
QmInsertTag |
Auth required? |
Yes - user must hold the key ROBOT and CALLMONITOR_ADDTAGS |
XML-RPC method |
QM.insertRecordTag |
Available since |
14.06 |
See also |
Example
curl --user robot:robot -i -H "Content-Type: application/json" -X GET "http://localhost:8084/queuemetrics/QmInsertTag/jsonStatsApi.do? id=664745.1 &filename=abcd.wav &time=5 &duration=7 &message=This+is+a+tag &color=FF0000"
Parameters
-
'server': the server name in a cluster setup or empty for a not cluster setup.
-
'id': the Asterisk call-id. (*)
-
'filename': the recording filename associated to the tag to be inserted.
-
'time': the time (in seconds) where the tag will be placed. If empty, the tag will be placed at the beginning of the file.
-
'duration': the tag duration (in seconds). It can be empty.
-
'message': a text message. If empty, no tags will be added. This is useful for retrieve the list of tags associated to a specific call.
-
'color': a color in RGB format (from 000000 to FFFFFF).
Parameters marked with an asterisk are mandatory.
Response
There is only one response block returned, named "TagRecords", where the caller will retrieve the list of tags associated to the specific server and UniqueId parameters.
Add broadcast messages: QmBroadcastMsg
This method is used to insert broadcast messages that will be shown in the realtime broadcast message page.
Method |
QmBroadcastMsg |
Auth required? |
Yes - user must hold the key ROBOT |
XML-RPC method |
QM.broadcastMessage |
Available since |
14.06 |
See also |
Example
curl --user robot:robot -i -H "Content-Type: application/json" -X GET "http://localhost:8084/queuemetrics/QmBroadcastMsg/jsonStatsApi.do? text=Hello+world &everyone=1"
Parameters
-
'text': the message to be broadcast. (*)
-
'queue': the optional queue name to act as a filter (may be empty).
-
'location': the optional location name to act as a filter (may be empty).
-
'supervisor': a supervisor login to act as a filter (may be empty). The message will be broadcast to people reporting to that supervisor.
-
'agent': a specific destination agent (may be empty). The message will be addressed to the specified agent.
-
'everyone': set to "1" to have the message delivered to everyone.
Parameters marked with an asterisk are mandatory.
Authentication and agent information
Checking logins: QmAuth
This method is used to authenticate a username / password set against the QueueMetrics server. This can be used by third-party software that does not want to keep its own separate user database but wants to use QueueMetrics' instead.
Method |
QmAuth |
Auth required? |
Yes |
XML-RPC method |
QM.auth |
Available since |
14.06 |
See also |
Superceded by QmAuthenticate |
Example
curl --user robot:robot -i -H "Content-Type: application/json" -X GET "http://localhost:8084/queuemetrics/QmAuth/jsonStatsApi.do"
Parameters
None. You only pass the authentication.
Response
The call will return one single block named "auth".
This block contains the following information:
-
'UserName': the login name.
-
'Status': OK if authentication was accepted or ERR if it was refused.
-
'FullName': The user’s full name.
-
'Email': The user’s email address.
-
'Class': The name of the class the user belongs to.
-
'Keys': The active key set of the user, that is, all keys given to the class plus or minus the keys that have been granted or revoked to this specific user.
-
'Masterkey': If set to 1, this user has a Masterkey, so this user will pass each key ckeck.
-
'NLogons': The number of logons the user has made. Each successful QmAuth call counts as a logon.
Authentication and password changing: QmAuthenticate
This method is used to obtain the profile of a user given its login and password. The profile is made up of both login and - where applicable - agent information. It is possible to obtain the profile either of the very user you are calling (by knowing its login and password) or of a "deferred" separate user, if you have a user that would have the admin keys to view that information in the main GUI.
The deferred username works so that:
-
If a deferred username is passed, and…
-
If the username/login pair are valid and the user has key USRADMIN and ROBOT
-
Then the User.* output for the deferred user is returned
-
If the user also holds the key USR_AGENT, the Agent.* output is returned as well
-
-
The password-change function applies only to the user who logs in, not to the deferred user.
Method |
QmAuthenticate |
Auth required? |
Yes |
XML-RPC method |
QM.authenticate |
Available since |
14.06 |
See also |
Example
curl --user robot:robot -i -H "Content-Type: application/json" -X GET "http://localhost:8084/queuemetrics/QmAuthenticate/jsonStatsApi.do? deferred=agent/101"
Logs on as "robot" and obtains information about "agent/101".
Parameters
-
'deferred': the other user you are accessing data for. If left out, the authenticating user is used.
-
'newpass': the new password to be changed for the user. If left blank, the password is not set.
Parameters marked with an asterisk are mandatory.
Response
There is only one response block returned, named "output", where the caller will retrieve all user data, including the live key set for that user.
The output block has the format:
Column 0 | Column 1 | Explanation |
---|---|---|
user.user_id |
173 |
Internal user-id |
user.login |
Agent/101 |
|
user.real_name |
John Doe |
|
user.class_name |
AGENTS |
|
user.keys |
USER AGENT XX YY |
All computed keys, space-separated |
user.n_logons |
37 |
|
user.last_logon |
2011-10-08 12:34:56 |
|
user.comment |
Optional |
|
user.token |
876543 |
Optional |
user.email |
Optional |
|
user.enabled |
true |
"true" or "false" |
agent.id |
86 |
Internal agent-id |
agent.description |
Agent J.D. (101) |
The name displayed in reports |
agent.aliases |
A set of aliases (if present) |
|
agent.location |
Main |
Blank if none |
agent.group_name |
Experienced agents |
Blank if none |
agent.current_terminal |
Sip/1234 |
Blank or "-" if none |
agent.vnc_url |
Optional |
|
agent.supervised_by |
Demoadmin |
Blank if none, or login of the supervisor |
agent.xmpp_address |
xmpp:101@myserver |
XMPP chat address |
agent.visibility_key |
Optional |
|
agent.payroll_code |
Optional |
|
password.changed |
OK |
OK if password was changed, blank otherwise |
The following rules apply:
-
Column zero contains the attribute.
-
Column one contains the value of the attribute (we supply a sample in the table above).
-
Attribute names are not case sensitive.
-
If the user is also an agent, that is, there is an agent under the same name as the login, Agent attributes are passed.
-
Blank attributes may or may not be present in the list of attributes.
The same information can also be accessed and edited through the Configuration API. |
The set of known queues for an agent: QmAgentQueues
Given an agent (like Agent/101) let the caller know on which queue(s) he’s supposed to work, as per the configuration on the QM interface. For each queue, we get also back a "level", that is a penalty level, like 0, 1 or 2.
It will also return the composite queues the agent is known on and the level he’s scheduled on them.
Method |
QmAgentQueues |
Auth required? |
Yes - user must hold the key ROBOT |
XML-RPC method |
QM.getQueuesForAgent |
Available since |
14.06 |
See also |
Example
curl --user robot:robot -i -H "Content-Type: application/json" -X GET "http://localhost:8084/queuemetrics/QmAgentQueues/jsonStatsApi.do? agent=Agent/101"
Parameters
-
'agent': the agent code we want to retrieve. (*)
Parameters marked with an asterisk are mandatory.
Response
If the agent code is unknown, an exception is raised.
There is only one response block returned, named "output", where the caller will retrieve all user data, including the live key set for that user.
The output block has the format:
Column 0 | Column 1 | Column 2 | Column 3 |
---|---|---|---|
Agent/101 |
Q1 |
Queue 1 |
0 |
Agent/101 |
Q2 |
My Queue 2 |
2 |
Agent/101 |
Q3 Q4 |
Monitor 3 & 4 |
1 |
Explanation as follows:
-
Column zero contains the agent code.
-
Column one contains the queue or composite queue it is known for. These are a set of the queues as they are known in Asterisk. They are separated by either a space or a vertical pipe (|) symbol.
-
Column two contains the name that such queue(s) appear in the QM interface
-
Column three contains the agent level, as per:
-
0: Main (no penalty).
-
1: Wrap (some penalty).
-
2: Spill (highest penalty).
-
The available pause codes for an agent: QmAgentPCodes
Get the current association of agents to queues.
Given an agent (e.g. "Agent/101"), the caller gets back a set of pause codes and their description as it would be visible to this agent. As QM allows protecting pause codes with security keys (so that e.g. you can have some pauses visible by some users only) QM computes the set of allowed pause from the point of view of the agent.
Method |
QmAgentPCodes |
Auth required? |
Yes - user must hold the key ROBOT |
XML-RPC method |
QM.getPauseCodesForAgent |
Available since |
14.06 |
See also |
Example
curl --user robot:robot -i -H "Content-Type: application/json" -X GET "http://localhost:8084/queuemetrics/QmAgentPCodes/jsonStatsApi.do? agent=Agent/101"
Parameters
-
'agent': the agent code we want to retrieve. (*)
Parameters marked with an asterisk are mandatory.
Response
If the agent code is unknown, an exception is raised.
There is only one response block returned, named "output", where the caller will retrieve all user data.
The output block has the format:
Column 0 | Column 1 | Column 2 | Column 3 |
---|---|---|---|
Agent/101 |
03 |
Lunch break |
PNB |
Agent/101 |
17 |
PB |
|
Agent/101 |
26 |
Coffee break |
NPNB |
Explanation as follows:
-
Column 0 contains the agent code.
-
Column 1 contains the pause code, as should be reported in Asterisk.
-
Column 2 is the description.
-
Column 3 is the pause type:
-
'PB' - pause is payable and billable.
-
'PNB' - pause is payable but not billable.
-
'NPB' - pause is not payable but billable (unlikely!).
-
'NPNB' - pause is neither payable nor billable.
-
Quality Assessment (QA)
Retrieving QA statistics: QmQaReport
This method is very similar to QM.stats
but it’s used to retrieve Quality Assessment statistics.
Method |
QmQaReport |
Auth required? |
Yes - user must hold the key ROBOT |
XML-RPC method |
QM.qareport |
Available since |
14.06 |
See also |
Example
curl --user robot:robot -i -H "Content-Type: application/json" -X GET "http://localhost:8084/queuemetrics/QmQaReport/jsonStatsApi.do ?from=2000-01-01.00:00:00 &to=2015-01-01.00:00:00 &queues=q1|q2 &form=MyForm &block=QualAssDO.TrkCalls &block=QualAssDO.Res1"
Parameters
-
'queues': one or more queues, separated by the pipe "|" symbol. (*)
-
'from': the beginning of the reporting period, in date-time format. (*)
-
'to': the end period. (*)
-
'agent': the agent code to be used as a filter.
-
'form': the form you want to report on. (*)
-
'grader': the grader type.
-
'block': One or more data blocks that you need to access.
Parameters marked with an asterisk are mandatory.
For a quick reference, available data blocks are also listed in Appendix II of this manual at Available blocks for QA.
Raw form data: QmQaFormReport
Reads a list of filled in QA forms within the requested period.
Method |
QmQaFormReport |
Auth required? |
Yes - user must hold the key ROBOT |
XML-RPC method |
QM.qaformreport |
Available since |
14.06 |
See also |
Example
curl --user robot:robot -i -H "Content-Type: application/json" -X GET "http://localhost:8084/queuemetrics/QmQaFormReport/jsonStatsApi.do ?from=2000-01-01.00:00:00 &to=2015-01-01.00:00:00 &agent=agent/101 &queues=q1|q2 &form=MyForm &block=QualAssFormDO.FormStructure &block=QualAssFormDO.SectionValues &block=QualAssFormDO.Comments"
Parameters
-
'queues': one or more queues, separated by the pipe "|" symbol. (*)
-
'from': the beginning of the reporting period, in date-time format. (*)
-
'to': the end period. (*)
-
'agent': the agent code to be used as a filter.
-
'form': the form you want to report on. (*)
-
'grader': the grader type.
-
'block': One or more data blocks that you need to access.
Parameters marked with an asterisk are mandatory.
For a quick reference, available data blocks are listed in Appendix II of this manual at Available blocks for QA.
QA form summaries: QmQaFormSummary
This method is very similar to QmStats but it’s used to retrieve aggregated information about a specific Quality Assessment Form.
The report counts the aggregated QA statistics on calls with timestamp included in the date range specified.
Method |
QmQaFormSummary |
Auth required? |
Yes - user must hold the key ROBOT |
XML-RPC method |
QM.qaformsummary |
Available since |
14.06 |
See also |
Example
curl --user robot:robot -i -H "Content-Type: application/json" -X GET "http://localhost:8084/queuemetrics/QmQaFormSummary/jsonStatsApi.do ?from=2000-01-01.00:00:00 &to=2015-01-01.00:00:00 &queues=q1|q2 &form=MyForm &block=QualAssDO.OverallAverageFormReport &block=QualAssDO.ScoringItemsFormSummary"
Parameters
-
'queues': one or more queues, separated by the pipe "|" symbol. (*)
-
'from': the beginning of the reporting period, in date-time format. (*)
-
'to': the end period. (*)
-
'agent': the agent code to be used as a filter.
-
'form': the name of the form you want to report on. (*)
-
'grader': the grader type.
-
'block': One or more data blocks that you need to access.
Parameters marked with an asterisk are mandatory.
For a quick reference, available data blocks are listed in Appendix II of this manual at Available blocks for QA.
Entering a QA form: QmQaGrading
This method lets you fill a QA form through an API call. It replies with the same raw information reported by the 'QmQaFormReport' method and can replace it if QA parameters are empty when calling.
The report counts the aggregated QA statistics on calls with timestamp included in the date range specified.
Method |
QmQaGrading |
Auth required? |
Yes - user must hold the key ROBOT and the key QA_TRACK |
XML-RPC method |
QM.qaformgrading |
Available since |
14.06 |
See also |
Example
curl --user robot:robot -i -H "Content-Type: application/json" -X GET "http://localhost:8084/queuemetrics/QmQaGrading/jsonStatsApi.do ?calldate=2014-03-30.15:19:00 &margin=3600 &id=475263.1 &form=MyForm &queues=q1 &item_CLE=73 &item_HEL=56 &comment=Comment1 &comment=Comment2 &block=QualAssFormDO.FormStructure &block=QualAssFormDO.SectionValues &block=QualAssFormDO.Comments"
Parameters
-
'queues': the set of queues that must be included in the analysis. They must be separated by a "|" symbol if more than one queue is passed. The queue name is the internal Asterisk queue name. (*)
-
'calldate': the beginning of the search period for the call. This should be usually a few seconds or minutes before the call was started. (*)
-
'margin': This is at least the number of seconds the call was in the waiting status (or the complete call time or a suitable number that comfortably contains the call like, for example, 3600). (*)
-
'form': The form name that you need to fill-in. (*)
-
'id': The unique identifier for the call to be graded. (*)
-
'grader': The grader type used to filter out graded forms.
-
'item_': The list of QA items score supplied as an hash of "item_" prefix (see above). The list should contain all specific form items codes and their relative score. In order to specify N/A values for not mandatory items, an empty string should be specified. If the list is left empty, no QA score will be filled into the form (*)
-
'comment': A list of the notes to be filled in the form. Each note must be supplied as a String. If the list is empty, no new comments will be added to the form.
-
'block': a set of blocks to be returned. Possible values are the ones defined in 'QmQaFormReport'.
Parameters marked with an asterisk are mandatory.
For a quick reference, available data blocks are listed in Appendix II of this manual at Available blocks for QA.
Finding calls to grade: QmQaCallsToGrade
Runs a Grading transaction.
Method |
QmQaCallsToGrade |
Auth required? |
Yes - user must hold the key ROBOT |
XML-RPC method |
QM.qacallstograde |
Available since |
14.06 |
See also |
Example
curl --user robot:robot -i -H "Content-Type: application/json" -X GET "http://localhost:8084/queuemetrics/QmQaCallsToGrade/jsonStatsApi.do ?from=2010-01-01.00:00:00 &to=2014-06-30.00:00:00 &form=MyForm &queues=q1|q2 &block=QAGradingDO.qagExtendedProposals &k_outcome_KN_min=100 &k_outcome_KN_num= &k_agroup_Default_min=1"
Parameters
-
'queues': the set of queues that must be included in the analysis. They must be separated by a "|" symbol if more than one queue is passed. The queue name is the internal Asterisk queue name. (*)
-
'from': a start date. (*)
-
'to': an end date. (*)
-
'form': the name of the form. (*)
-
'agent': an optional agent code to be used as a filter.
-
'k_': a hash of constrainsts used to find calls (see below).
-
'block': one or more response blocks.
Parameters marked with an asterisk are mandatory.
For a quick reference, available data blocks are listed in Appendix II of this manual at Available blocks for QA.
Understanding constraints
Constraints are a set of 'key, value' pairs used by the engine to filter out the calls to be graded. The constraint list should be defined with the proper syntax in order to be correctly interpreted by QueueMetrics.
There are two types of constraints: the percentage values and the absolute values. They should be respectively specified through the suffixes "min" or "num".
The constraints are related to different categories:
-
Individual agents: specified through the key 'AXG' (like, for example: AGX_min or AGX_num)
-
All calls: specified through the key 'AC' (like, for example: AC_min or AC_num)
-
Outcome code: specified through the key 'outcome' followed by the outcome code and separated by an underscore character (like, for example: outcome_KN_num or outcome_KN_min)
-
Agent group: specified through the key 'agroup' followed by the agent group name and separated by an underscore character (like, for example: agroup_Default_min or agroup_Default_num)
Tasks
Tasks have two concepts that you have to keep in mind when accessing them through the API:
-
Validity: a task can have a validity period, that might be current or future. A task with a futiure validity will "mature" when it enters the validity period.
-
The Task Process Field: This is an optional identifier defined as 'ProcessFamily/ProcessId' to be associated to the task. Either ProcessFamily and/or ProcessId might be empty. It is used generally to link tasks to external processes, e.g. the process and ID of an external system that loads tasks for users.
Live data: QmAddNoteTask
Adds a note task for a specific user.
Method |
QmAddNoteTask |
Auth required? |
Yes - user must hold the key ROBOT |
XML-RPC method |
QM.tskAddNote |
Available since |
14.06 |
See also |
Example
curl --user robot:robot -i -H "Content-Type: application/json" -X GET "http://localhost:8084/queuemetrics/QmAddNoteTask/jsonStatsApi.do? recipient=Agent/101 &valid_from=2010-01-01.00:00:00 &message=Hello+World ¬es=notes+here"
Parameters
-
'recipient': the login of the user receiving the task. (*)
-
'valid_from': begin of validity (in long date format). See above.
-
'valid_to': end of validity.
-
'process': usually in the form "ProcessFamily/ProcessID". See above.
-
'message': the message associated with the task. (*)
-
'notes': an optional textual note.
Parameters marked with an asterisk are mandatory.
Live data: QmAddTrainingTask
Adds a training task for a specific user.
Method |
QmAddTrainingTask |
Auth required? |
Yes - user must hold the key ROBOT |
XML-RPC method |
QM.tskAddTraining |
Available since |
14.06 |
See also |
Example
curl --user robot:robot -i -H "Content-Type: application/json" -X GET "http://localhost:8084/queuemetrics/QmAddTrainingTask/jsonStatsApi.do? recipient=Agent/101 &valid_from=2010-01-01.00:00:00 &message=Hello+World ¬es=notes+here &training_title=QM+Website &training_url=http://queuemetrics.com"
Parameters
-
'recipient': the login of the user receiving the task. (*)
-
'valid_from': begin of validity (in long date format). See above.
-
'valid_to': end of validity.
-
'process': usually in the form "ProcessFamily/ProcessID". See above.
-
'message': the message associated with the task. (*)
-
'notes': an optional note.
-
'training_title': a title for this trainig task. (*)
-
'training_url': an URL for this training task. (*)
-
'training_id': an optional ID for this training task.
Parameters marked with an asterisk are mandatory.
Live data: QmAddMeetingTask
Adds a meeting task for a specific user.
Method |
QmAddMeetingTask |
Auth required? |
Yes - user must hold the key ROBOT |
XML-RPC method |
QM.tskAddMeeting |
Available since |
14.06 |
See also |
Example
curl --user robot:robot -i -H "Content-Type: application/json" -X GET "http://localhost:8084/queuemetrics/QmAddMeetingTask/jsonStatsApi.do? recipient=Agent/101 &valid_from=2010-01-01.00:00:00 &title=Hello &message=Hello+World ¬es=notes+here &date=2014-05-09.10:30:00 &duration=300"
Parameters
-
'recipient': the login of the user receiving the task. (*)
-
'valid_from': begin of validity (in long date format). See above.
-
'valid_to': end of validity.
-
'process': usually in the form "ProcessFamily/ProcessID". See above.
-
'message': the message associated with the task. (*)
-
'notes': an optional note.
-
'date': a date and time for the meeting. (*)
-
'duration': the duration of the meeting, in seconds. (*)
Parameters marked with an asterisk are mandatory.
PBX Interactions
Triggering PBX actions
This method is used to remotely trigger actions that are performed by the PBX(s) connected to QueueMetrics. By this way an external robot can login/out agents, perform pause/unpause actions and other PBX related operations normally triggered by QueueMetris through the agent’s realtime and the realtime view.
Method |
qm_jsonsvc_do_pbxactions.do |
Auth required? |
Yes - user must hold the key ROBOT |
XML-RPC method |
QM. |
Available since |
15.02.5 |
See also |
These interactions may raise an error if they cannot be performed (e.g. wrong AMI port configured on QueueMetrics) but if the request can be queued to an Asterisk server they are considered okay whether they succeed or not a the Asterisk level.
Each operation has its own set of parameters that should be present in order to generate a valid action. A set of optional parameters can be added; these optional parameters (specified by an optional array of string) are set as a channel variable by the dialplan (optional parameters are not set as channel variables anymore, since 16.10.13). A PHP script sample is provided through github (see the table above). The script aims to provide an easy startup for developers needs to interact with PBX actions in QueueMetrics.
Parameters
-
action : either login, logout, join, remove, pause, unpause, calloutcome, customdial, sendtext, softhangup, transfer, inboundmonitor, outboundmonitor.
-
queues : array of queues. Needed by join, remove, customdial, actions.
-
extension : agent extension. Needed by all actions except for logout.
-
server : If empty the default QueueMetrics server is used, otherwise asterisk server identifier in cluster mode. Needed by all actions.
-
agent : Agent code. Nededed by login, logout, join, remove, pause, unpause, softhangup, transfer, inboundmonitor, outboundmonitor.
-
pause : Pause code. Needed by pause action.
-
callid : Asterisk call Id identifying a specific live call. Needed by calloutcome, softhangup, transfer actions.
-
outcome : Outcome code. Neded by the calloutcome action.
-
targetext : Target extension. Needed by customdial, sendtext, transfer, inboundmonitor, outboundmonitor.
-
message : ASCII message to be sent through the sendtext actions (only available for Asterisk 10+).
-
optValues : A set of optional values that are propagated by QueueMetrics to the dialplan as a custom channel variables. The array shoudl be populated with key/value set where key and values should be appended to the array as a separate line. For further information please see the PHP sample script provided.
Following there’s a list of example calls for each of the available functions:
Join
curl --user robot:robot -H "Content-Type: application/json" -X POST -d '{"action":"join", "extension":"", "queues": ["300","301"], "agent": "Agent/200", "server": ""}' "http://localhost:8080/queuemetrics/qm_jsonsvc_do_pbxactions.do"
Remove
curl --user robot:robot -H "Content-Type: application/json" -X POST -d '{"action":"remove", "extension":"", "queues": ["300","301"], "agent": "Agent/200", "server": ""}' "http://localhost:8080/queuemetrics/qm_jsonsvc_do_pbxactions.do"
Pause
curl --user robot:robot -H "Content-Type: application/json" -X POST -d '{"action":"pause", "extension":"", "pause": "10", "agent": "Agent/200", "server": ""}' "http://localhost:8080/queuemetrics/qm_jsonsvc_do_pbxactions.do"
Unpause
curl --user robot:robot -H "Content-Type: application/json" -X POST -d '{"action":"unpause", "extension":"", "agent": "Agent/200", "server": ""}' "http://localhost:8080/queuemetrics/qm_jsonsvc_do_pbxactions.do"
Custom Dial
curl --user robot:robot -H "Content-Type: application/json" -X POST -d '{"action":"customdial", "extension":"200","targetext":"201","queues":"301", "server": ""}' "http://localhost:8080/queuemetrics/qm_jsonsvc_do_pbxactions.do"
Call Outcome
curl --user robot:robot -H "Content-Type: application/json" -X POST -d '{"action":"calloutcome", "callid":"1489669688.208", "outcome": "a", "server": ""}' "http://localhost:8080/queuemetrics/qm_jsonsvc_do_pbxactions.do"
Add Feature
curl --user robot:robot -H "Content-Type: application/json" -X POST -d '{"action":"addfeature", "callid":"1489669688.208", "outcome": "fc01", "server": ""}' "http://localhost:8080/queuemetrics/qm_jsonsvc_do_pbxactions.do"
Remove Feature
curl --user robot:robot -H "Content-Type: application/json" -X POST -d '{"action":"remfeature", "callid":"1489669688.208", "outcome": "fc01", "server": ""}' "http://localhost:8080/queuemetrics/qm_jsonsvc_do_pbxactions.do"
Soft Hangup
curl --user robot:robot -H "Content-Type: application/json" -X POST -d '{"action":"softhangup", "extension":"200", "agent":"Agent/200", "callid":"1489669688.208", "server": ""}' "http://localhost:8080/queuemetrics/qm_jsonsvc_do_pbxactions.do"
Transfer
curl --user robot:robot -H "Content-Type: application/json" -X POST -d '{"action":"transfer", "extension":"200", "targetext":"202", "callid":"1489670009.216", "agent":"agent/200", "server": ""}' "http://localhost:8080/queuemetrics/qm_jsonsvc_do_pbxactions.do"
Inbound Monitor
curl --user robot:robot -H "Content-Type: application/json" -X POST -d '{"action":"inboundmonitor", "extension":"SIP/200", "targetext":"202", "callid":"1489670410.229", "agent":"agent/200", "server": ""}' "http://localhost:8080/queuemetrics/qm_jsonsvc_do_pbxactions.do"
Outbound Monitor
curl --user robot:robot -H "Content-Type: application/json" -X POST -d '{"action":"outboundmonitor", "extension":"SIP/200", "targetext":"202", "callid":"1489670410.229", "agent":"agent/200", "server": ""}' "http://localhost:8080/queuemetrics/qm_jsonsvc_do_pbxactions.do"
Action customdial and hot-desking
Generally speaking, to do outbound dialling you need to know the agent’s extension you want to ring. Of course, this is more complex when running in hotdesking mode, as agent and extension are totally separate.
To make this easier to run, since QM 20.11.3, the behavior is that:
-
if hotdesking mode is enabled,
-
and if agent extension passed in the field
extension
starts withAgent/
, -
and if
Agent/XXX
is logged on with a known extension on the outbound queue
then QM will:
-
run a report for required queue for the current real-time visibility interval,
-
will find whether
Agent/XXX
is logged on and will get its extension code, -
will use that channel for outbound dialling as the agent’s channel.
If the agent is not logged on, or the extension is empty, then the webservice will abort with an error. If the agent is paused, then a call will still be made.
In practice
First, make sure that you have an Asterisk queue you use as a placeholder for outbound. Only agents logged on to this queue will be able to dial out. In the example below, we created a queue "999" and marked it as "outbound" in the queue definition in QM, so it appears with a yellow icon.
We then make sure agent/101 is logged on to an extension in hotdesking (in our case, extension 300).
Upon calling:
curl --user robot:robot -H "Content-Type: application/json" -X POST -d '{"action":"customdial", "extension":"agent/101", "message":"", "targetext":"5551234", "queues":"999", "server": ""}' "http://127.0.0.1:8080/queuemetrics/qm_jsonsvc_do_pbxactions.do"
You get a response OK and an outbound call is started on extension 300 and a second leg to number 5551234 is started as soon as the agent answers; on the agent’s page, on Realtime and in reports, the call belongs to Agent/101.
If you try calling an agent when they are not logged on, you get the following response:
{ "action" : "", ...., "resultStatus" : "KO: Agent: 'Agent/102' not logged on" }
And no call is placed.
Action customdial and penalties
When joining on a queue, QueueMetrics is not able to retrieve the proper queue/agent penalty association.
If you need to login agents with their own penalty for the specified queues,
the calling script should set and specify QM_AGENT_PRIONUM
and QM_AGENT_PRIOLBL
as optional variables like in the PHP example below
joinMember("204", "agent/101", array('300','400'), 'trix1', array("QM_AGENT_PRIONUM"=>"1", "QM_AGENT_PRIOLBL"=>"M"));
System administration
Updating the activation key: QmSetActivationKey
This method is used to remotely change the license key of the QueueMetrics instance or to query the current license key.
As this operation is potentially critical, the user sending this request must hold the keys ROBOT and KEYUPDATE. We ship such a user named 'keyupdater' in the default QM configuration but it has to be manually enabled. Make sure you change the password as well.
As the system must be restarted after setting the new key so that it is picked up (this is done automatically), the QM server may be unavailable for a few seconds during the restart phase and all current user sessions may be forcibly terminated. It is therefore not advisable to run this command on a busy system with many users logged in.
Method |
Qm |
Auth required? |
Yes - user must hold the key ROBOT and KEYUPDATE |
XML-RPC method |
QM. |
Available since |
14.06 |
See also |
Example
curl --user keyupdater:enableme -i -H "Content-Type: application/json" -X GET "http://localhost:8084/queuemetrics/QmSetActivationKey/jsonStatsApi.do ?key=1234"
Parameters
-
'key': the new activation key. (*)
Parameters marked with an asterisk are mandatory.
Response
The custom block "KeyResults" is filled with the following parameters:
-
KEY_status : NOKEY if no new key is given, otherwise OK or ERROR depending on the success of the operation.
-
KEY_plexId : The server identifier.
-
KEY_message : A message explaining what went wrong.
-
KEY_current_appl : The name of the application.
-
KEY_current_user : The name of the user that the application is licensed to.
-
KEY_current_exp : The expiration date for the current key.
Please note that when a new key is installed, the current user and expiration date are those of the system on which the key is being installed; you should get the new ones as soon as the system restarts (will usually take between 5 and 20 seconds).
Call Queries
Call queries are expressions, written in a micro-language, that let you filter by call on a report. These filters are applied on the possible data set that is delimited by the time period and the queues specified.
An example query could be:
(or (and (CODA_F_calldur_min 10) (CODA_F_calldur_min 20)) (and (CODA_F_calldur_min 40) (CODA_F_calldur_min 60)))
As those expressions can be arbitrarily nested, you can combine multiple clauses to get the exact set of calls you are looking for. In the example above, we are looking for all calls that have a duration between 10 and 20 seconds, or between 40 and 60 seconds.
Valid logical filters are:
-
and
-
or
-
nor
: the opposite ofor
, that is, not. -
=t=
: the value True -
=f=
: the value False
All logical filters take at least one argument an up to how many you need.
The outermost form of the query must be a logical filter, even if there is only one single form. So (CODA_F_wait_min 200)
is not a valid filter, but (and (CODA_F_wait_min 200))
is.
Physical filters, displayed in the table below, accept one or two parameters. They are passed in as strings.
-
If the parameter is invalid, the filter is considered invalid and not applied, that is, skipped.
-
In general, filters that accept a string value will also accept a regular expression.
-
All filters work on the IDs passed by Asterisk, that is, if you have a queue which ID is "300" that is decoded to "Support", the filter will expect the value "300".
All filters you run in QueueMetrics are implemented in terms of a combination of these physical filters.
Physical filter | Meaning | Parameters |
---|---|---|
CODA_F_agenteFiltro |
The agent code |
(s) |
CODA_F_outcome |
The outcome |
(s) |
CODA_F_calltags |
The call tag |
(s) |
CODA_F_features |
The feature |
(s) |
CODA_F_callskills |
The skill |
skill(s), value(i) |
CODA_F_atomicQueueFilter |
A queue |
(s) |
CODA_F_server |
A server id |
(s) |
CODA_F_disconnection |
A disconnection code |
(s) |
CODA_F_asteriskid |
An UniqueId |
(s) |
CODA_F_caller |
A caller’s number |
(s) |
CODA_F_nrm_caller |
A normalized caller’s number |
(s) |
CODA_F_dnis |
A DNIS |
(s) |
CODA_F_ivr |
An IVR sequence |
(s) |
CODA_F_wait_min |
Min wait |
(i) |
CODA_F_calldur_min |
Min duration |
(i) |
CODA_F_enterpos_min |
Min enter position |
(i) |
CODA_F_attempts_min |
Min attempts |
(i) |
CODA_F_wait_max |
Max wait |
(i) |
CODA_F_calldur_max |
Max call duration |
(i) |
CODA_F_enterpos_max |
Max enter position |
(i) |
CODA_F_attempts_max |
Max attempts |
(i) |
CODA_F_noncont_days |
Days |
A string with the days of the week (s) |
CODA_F_noncont_r1_from |
Time 1 from |
A time HH:MM or HH:MM:SS (s) |
CODA_F_noncont_r1_to |
Time 1 to |
A time HH:MM or HH:MM:SS (s) |
CODA_F_shortcall_wait |
Min wait |
(i) |
CODA_F_shortcall_talk |
(i) |
|
CODA_F_shortcall_attempt |
(i) |
|
CODA_F_variables |
Variable |
variable (s) value (i) |
CODA_F_lostAttemptFor |
The agent code |
(s) |
In the parameters column, '(s)' is a string parameter, while '(i)' an integer one.
Example
curl --user robot:robot -i -H "Content-Type: application/json" -X GET "http://localhost:8080/qm/QmStats/jsonStatsApi.do? queues=9003%7C93229004%7C9001%7C9002%7C9007%7C9008%7C9005%7C9104%7C9006 &from=2000-01-01.00:00:00 &to=2020-01-01.00:00:00 &block=OkDO.RiassAllCalls &block=OkDO.AgentsOnQueue &query=%28and%20%28CODA_F_wait_min%2020%29%29"
This query runs a report on queues 9003|93229004|9001|9002|9007|9008|9005|9104|9006
with the filter (and (CODA_F_wait_min 200))
, that is,
returns all calls that waited more than 200 seconds. Note how the parameters have been URL-encoded.