Import API
Available in 9.3 and above
Overview
The Import API allows ingesting 3rd party or Verba data into the system.
- 1 Overview
- 2 Prerequisites
- 3 General guidelines
- 3.1 HTTP GET, POST
- 3.2 URL encoding
- 3.3 Response type
- 3.4 Security
- 4 Authentication
- 4.1 Request
- 4.1.1 Authentication request
- 4.2 Response
- 4.2.1 Authentication response
- 4.1 Request
- 5 Import request
- 5.1 Request
- 5.1.1 Authentication request
- 5.2 Response
- 5.2.1 Authentication response
- 5.2.2 HTTP/1.1 201 OK
- 5.1 Request
- 6 XML description
- 6.1.1 Call example XML
- 6.1.2 SMS example XML
- 6.2 Trader voice example XML
- 6.2.1 CDR record
- 6.2.2 Media record
- 7 Load Balancing
The primary goal of the interface is to enable ingesting records to the system using JSON or XML formatted metadata and the corresponding media file(s). The interface provides access to the Verba Import Service through a REST API. This API supports both the standard and the advanced (trader voice specific) database schemas: Data model for trader voice recordings.
The API can be reached at http(s)://media-repository-address:port/restapi/v093/import/<action>
Prerequisites
In order to utilize the API, the following configuration is needed in the Web Application: Prerequisite configuration for Import API
General guidelines
HTTP GET, POST
The functions of the API are available as simple HTTP GET and POST requests. For implementations, where HTTP POST is not available, you can use the HTTP GET method. The maximum length of the HTTP GET request is usually maximized either by the client or the server. The client should assume that the maximum length of a GET request is 4000 characters, although, some implementations may support longer URLs too.
URL encoding
All HTTP requests have to be URL encoded and all spaces and special characters have to be escaped and substituted with its URL encoded equivalent. For further information, see http://www.w3schools.com/TAGS/ref_urlencode.asp.
Response type
The API provides json formatted responses.
Security
The API provides the following mechanism to ensure that the communications between the external application and the recording system are secure:
Authentication
The Import API requires a valid session token to process import requests. The authentication expects an HTTP GET request to the auth action. The token generated after a successful authentication is valid for one hour after the last use.
If the authentication fails, the system will return a 500 HTTP Status Response, and a description of the problem encountered during the authentication
Request
Authentication request
GET /restapi/v093/import/auth
Host: hostname:port
apikey: D53B03F9-3A7D-4645-97E9-618FD38819A4
password: D87869A979DB0078521D5872944E966E
username: user
cache-control: no-cacheRequest headers
Field | Description |
|---|---|
apikey | The generated, unique GUID for the API key |
username | The username of the Verba user used to authenticate. This user must have the Conversation Import role. (optional) |
password | The md5hash of the password for the Verba user (optional) |
Response
Authentication response
HTTP/1.1 200 OK
Date: Thu, 09 Jan 2019 10:42:57 GMT
Content-Type: application/json
Content-Length: 70Response codes
Response Code | Description |
|---|---|
200 | Successful authentication |
500 | Error during authentication |
Response headers
Field | Description |
|---|---|
Date | The date and time of the request in EEE, DD MMM YYYY HH:MM:SS format
Type: String
|
Content-Type | The type of the HTTP content: application/json |
Content-Length | The length of the HTTP content |
Response body
{
"status" : "ok",
"token" : "94557faa725211e980f300155d01545a"
}{
"status" : "error",
"error_message" : "Internal Server Error. An unexpected error has occured while generating token: Bad token request. Provided userName and/or password is incorrect. (Note: password must be md5 hashed!)"
}Field | Description |
|---|---|
status |
|
token | The token for the authenticated session |
error_message | Description of the error encountered |
Import request
Request
The type of the request should be multipart, the boundary, media and the CDR file are mandatory unless noted otherwise. After a successful request, the following reply will be sent:
Authentication request
POST /restapi/v093/import/conversation HTTP/1.1
Host: 10.110.78.29:12345
apikey: D29AC60E-5CC3-48AE-9787-29E60EC1892A
token: 9471f4019e5611e980f800155d001c23
cache-control: no-cache
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name=""; filename="C:\GenericImport\CDR.xml
Content-Disposition: form-data; name=""; filename="C:\GenericImport\teszt.wav
------WebKitFormBoundary7MA4YWxkTrZu0gW--Request headers
Field | Description |
|---|---|
apikey | The generated, unique GUID for the API key |
token | The token received in the authentication request body |
Response
Authentication response
HTTP/1.1 200 OK
Date: Thu, 09 Jan 2019 10:42:57 GMT
Content-Type: application/json
Content-Length: 47Response codes
Response Code | Description |
|---|---|
200 | Successful import |
500 | Error during import |
HTTP/1.1 201 OK
JavaScript Object Notation: application/json
Object
Member Key: status
String value: ok
Key: status
Member Key: reason
String value: imported
Key: token
Response headers
Field | Description |
|---|---|
Date | The date and time of the request in EEE, DD MMM YYYY HH:MM:SS format
Type: String
|
Content-Type | The type of the HTTP content: application/json |
Content-Length | The length of the HTTP content |
Response body
{
"status" : "ok",
"reason": "imported"
}{
"status": "error",
"error_message": " Bad request. Failed to process CDR: String to parse is too short: , current position: 0"
}Field | Description |
|---|---|
status |
|
reason | Verification if the import is sucessful. |
error_message | Description of the error encountered |
XML description
The description of the Verba XML file can be found at Metadata XML fields. The id of the call is optional, if no ID is provided, the system will generate one.
Call example XML
<?xml version="1.0" encoding="utf-8"?>
<verbacdr state="1"> <!-- Finished Call State -->
<id>ff83f076-9e4e-11e9-80f8-00155d001c23</id>
<recorded_cid>testuser@verbalabs.com</recorded_cid>
<start_time>2019.06.21 14:40:15.618</start_time>
<end_time>2019.06.21 14:40:57.768</end_time>
<destination_caller_id>kakas@verbalabs.com</destination_caller_id>
<source_caller_id>6010</source_caller_id>
</verbacdr>SMS example XML
<?xml version="1.0" encoding="utf-8"?>
<verbacdr>
<source_caller_id>15198274350</source_caller_id>
<destination_caller_id>12038894142</destination_caller_id>
<start_time>2019.07.15 14:40:15.618</start_time>
<end_time>2019.07.15 14:40:15.618</end_time>
<modality_id>sms</modality_id>
<sms>test message</sms>
</verbacdr>Trader voice example XML
The Turret data model does not require a one-to-one relationship between metadata and media, it is allowed to have multiple CDR for one media file, or multiple media files for one CDR. The link between the media and CDR is the media_record_ids field. The media is found based on the CDR record by searching for the matching media record IDs, then limiting the search for media end time before CDR start time, and media start time after CDR end time.
CDR record
<?xml version="1.0" encoding="utf-8"?>
<verbacdr state="1"> <!-- Finished Call State -->
<type>1</type> <!-- CDR only -->
<id>dd0f1fea-4004-11e9-81ba-005056ac1d2e</id>
<rec_version>9.4.0 (Revision 5699r)</rec_version>
<native_id>588_0000000000</native_id>
<location>DEV-MR.VERBALABS.COM </location>
<source_device>257</source_device>
<source_caller_id>6001</source_caller_id>
<source_name>Mark Goodall</source_name>
<destination_caller_id>588</destination_caller_id>
<destination_name>Lloyds</destination_name>
<recorded_cid>6001</recorded_cid>
<signaling_source>10.10.64.46</signaling_source>
<start_time>2019.03.06 11:42:05.552</start_time>
<call_start_time>2019.03.06 11:42:05.552</call_start_time>
<end_time>2019.03.06 11:42:37.868</end_time>
<video_codec_id>299</video_codec_id> <!-- Undefined -->
<cause_id>0</cause_id> <!-- Normal -->
<rec_provider>11</rec_provider> <!-- BT ITS -->
<recorder_service_id>23</recorder_service_id> <!-- Unified Recorder -->
<modality_id>voice</modality_id>
<recorded_party>0</recorded_party> <!-- Source caller -->
<record_failed>false</record_failed>
<ondemand>false</ondemand>
<rtp_count_valid>false</rtp_count_valid>
<conference>false</conference>
<keep>false</keep>
<controlled>false</controlled>
<voice_mail>false</voice_mail>
<secondary>0</secondary> <!-- Primary -->
<agent_id>6001</agent_id>
<agent_name>Mark Goodall</agent_name>
<platform_id>bt-its</platform_id>
<media_record_ids>
<id>BT_IPSI-6-1-3</id>
</media_record_ids>
<files>
<file expected_url="2019\03\06\dd0f1fea-4004-11e9-81ba-005056ac1d2e_(20190306114205552).xml" original="1">2019\03\06\dd0f1fea-4004-11e9-81ba-005056ac1d2e_(20190306114205552).xml</file>
</files>
<markers>
<marker>
<comment>6002 left the call</comment>
<user>1</user>
<timestamp>2019.03.06 11:42:37.798</timestamp>
<start_pos>32</start_pos>
<end_pos>32</end_pos>
<marker_pos>1</marker_pos>
</marker>
</markers>
<participants>
<participant>
<callerid>6002</callerid>
<role>conferee</role>
<start_time>2019.03.06 11:42:05.552</start_time>
<end_time>2019.03.06 11:42:37.798</end_time>
<end_cause>0</end_cause>
</participant>
</participants>
<metadata>
<metadata_template type="bt-its" name="">
<calltype>Call</calltype>
<console>257</console>
<consolename/>
<consoletype>Netrix Button</consoletype>
<deviceid>65</deviceid>
<devicetype>Speaker</devicetype>
<line>588</line>
<linename>Lloyds</linename>
<linetype>Private Wire Automatic</linetype>
<phantomddi/>
<recchannel>6-1-3</recchannel>
<userName>Mark Goodall</userName>
<vertical>1539</vertical>
</metadata_template>
</metadata>
<media>
<mediasegment id="0" start_time="2019.03.06 11:42:05.552" end_time="2019.03.06 11:42:37.868">
<mediadescriptor>
<destination ip="127.0.0.1" port="16384" protocol="udp" tipsupported="false" />
<content type="main"/>
</mediadescriptor>
</mediasegment>
</media>
</verbacdr>Media record
<?xml version="1.0" encoding="utf-8"?>
<verbacdr state="1"> <!-- Finished Call State -->
<type>2</type> <!-- Media only -->
<id>dd0f1fec-4004-11e9-81ba-005056ac1d2e</id>
<rec_version>9.4.0 (Revision 5699r)</rec_version>
<native_id>BT_IPSI-6-1-3</native_id>
<location>DEV-MR.VERBALABS.COM</location>
<source_device>257</source_device>
<source_ip>10.10.69.35</source_ip>
<source_caller_id>6001</source_caller_id>
<source_name>Mark Goodall</source_name>
<destination_device>257</destination_device>
<destination_ip>10.10.69.35</destination_ip>
<destination_caller_id>6001</destination_caller_id>
<destination_name>Mark Goodall</destination_name>
<recorded_cid>6001</recorded_cid>
<start_time>2019.03.06 11:42:17.131</start_time>
<call_start_time>2019.03.06 11:42:11.191</call_start_time>
<media_start_time>2019.03.06 11:42:17.131</media_start_time>
<end_time>2019.03.06 11:42:43.013</end_time>
<audio_codec_id>2</audio_codec_id> <!-- G.711A 64 kbps -->
<video_codec_id>299</video_codec_id> <!-- Undefined -->
<cause_id>85</cause_id> <!-- Voice Inactivity -->
<rec_provider>11</rec_provider> <!-- BT ITS -->
<recorder_service_id>23</recorder_service_id> <!-- Unified Recorder -->
<modality_id>voice</modality_id>
<recorded_party>0</recorded_party> <!-- Source caller -->
<record_failed>false</record_failed>
<ondemand>false</ondemand>
<rtp_count_valid>false</rtp_count_valid>
<conference>false</conference>
<keep>false</keep>
<controlled>false</controlled>
<voice_mail>false</voice_mail>
<secondary>0</secondary> <!-- Primary -->
<agent_id>6001</agent_id>
<platform_id>bt-its</platform_id>
<media_length>25</media_length>
<media_record_ids>
<id>BT_IPSI-6-1-3</id>
</media_record_ids>
<files>
<file expected_url="2019\03\06\dd0f1fec-4004-11e9-81ba-005056ac1d2e_(20190306114211191).wav" size="42310" original="1">2019\03\06\dd0f1fec-4004-11e9-81ba-005056ac1d2e_(20190306114211191).wav</file>
</files>
<metadata>
<metadata_template type="bt-its" name="">
<console>257</console>
<consolename/>
<consoletype>Netrix Button</consoletype>
<deviceid>65</deviceid>
<devicetype>Intercom</devicetype>
<recchannel>6-1-3</recchannel>
<username>Mark Goodall</username>
<vertical>1539</vertical>
</metadata_template>
</metadata>
<media>
<mediasegment id="0" start_time="2019.03.06 11:42:11.200" end_time="2019.03.06 11:42:43.027">
<mediadescriptor>
<destination ip="10.10.10.10" port="1003" protocol="udp" tipsupported="false" />
<content type="main"/>
<codecs>
<codec name="PCMU" pt="0" clk="8000" />
<codec name="PCMA" pt="8" clk="8000" />
<codec name="G722" pt="9" clk="8000" />
<codec name="G729" pt="18" clk="8000" />
<codec name="G723" pt="4" clk="8000" />
<codec name="GSM" pt="3" clk="8000" />
</codecs>
<statistics>
<start_time>2019.03.06 11:42:11.201</start_time>
<rtp total="1597" lost="0" duplicated="0" outoforder="0" outofbuffer="0" streamchange="1"/>
<decoding ok="3194" error="0" skipped="0" outofbuffer="0" resync="12"/>
<mixing normalwrite="0" solowrite="3194" silencewrite="0" latemedia="0" resync="0" silence_suppressed="595"/>
</statistics>
</mediadescriptor>
</mediasegment>
</media>
<rec_quality total_score="100">
<recording rtploss="100" srtp="100" dec="100" mixing="100"/>
<media silence="100" noise="100" beep="100" amp_change="100" unnatural_silence="100" amp_envelope_variance="100" volume="100"/>
</rec_quality>
</verbacdr>
Load Balancing
The Import API for import service is a single server solution with no built-in load balancing capabilities. If multiple servers are required for the volume of the calls imported, client-side load balancing can be set up, as each separate server needs a session token unique to the server.