Версия API: 1.0

Если у Вас возник вопрос связанный с API, обратитесь в техническую поддержку [support@iptelefon.ru]

Общее описание

API работает по протоколу HTTP. Параметры передаются любым методом: POST или GET.
Ответ зависит от параметра заголовка Content-type. Пакет защищается секретным ключем.
Для доступа к API используется одна точка входа, информацию о которой Вы можете получить в личном кабинете.


Пример использования (PHP):

    
        $url = 'https://hive.iptelefon.su/hive/api/';	// Точка входа в API
        $secret = "fj0K55S96xjnUli34";			// Секретный ключ
        $post = array(
            'cell' => '8736',				// Номер контракта
            'method' => 'get-points',			//  Метод
        );

        $post['hash'] = md5(http_build_query($post) . $secret);

        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_HEADER, true);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post));

        $response = curl_exec($ch);
        $type = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);

        if ($type) {
    	    switch ($type) {
        	case 'application/json':
                    $content = substr($response, curl_getinfo($ch, CURLINFO_HEADER_SIZE));

                    print_r(json_decode($content, true));
                    break;
    	    }
    	}

        curl_close($ch);
    
    

Опции curl

CURLOPT_POST = true - передавать данные методом POST
CURLOPT_HEADER = true - выдвать http-заголовок вместе с содержимым (это требуется для извлечения полезной информации из заголовка, например, имя файла)
CURLOPT_RETURNTRANSFER = true - выдавать содержимое в переменную
CURLOPT_POSTFIELDS - полезная нагрузка

Интерпретация ответа

После получения ответа следует обратить внимание на параметр http-заголовка Content-type. Этот параметр указывает как необходимо интерпретировать полученное содержимое.

Content-type может быть:

application/json - строка в формате JSON
audio/wav - аудио файл в формате .wav
image/tiff - изображение в формате .tiff (обычно факс)
application/octet-stream - файл без указания формата

Пример обработки ответа

Пример ниже:

    
        $type = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);

        if ($type) {
            switch ($type) {
                case 'application/json':		   // Содержимое в формате JSON
                    $content = substr($response, curl_getinfo($ch, CURLINFO_HEADER_SIZE));

                    print_r(json_decode($content, true));
                    break;

                default:				// Содержимое файл
                    printf(" %-30s %s\n", "content type:", $type);
                    printf(" %-30s %s\n", "download speed:", curl_getinfo($ch, CURLINFO_SPEED_DOWNLOAD));
                    printf(" %-30s %s\n", "file size:", curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD));

                    if (!preg_match("/^Content-disposition: .*?filename=(.*)$/m", $response, $match)) {
                        echo "downloading file fail\n";
                        exit;
                    }

                    $file = substr($response, curl_getinfo($ch, CURLINFO_HEADER_SIZE));
                        $filename = trim($match[1]);

                        printf(" %-30s %s\n", "filename:", $filename);
                        file_put_contents("/tmp/" . $filename, $file);
            }
        }
    
    

Методы

Получение истории звонков (get-calls)

Параметры:

    
    	$post = array(
    	    'cell' => '8736',
    	    'method' => 'get-calls',

    	    'start' => '2016-02-03 00:00:00',	// начало периода
    	    'end' => '2016-02-03 23:59:59',	// конец периода
    	    'limit' => 0,			// ограничение выдачи. 0 - без ограничения

    	    'disposition' => 'any',		// статус звонка (any - любой,
    						// 'ANSWERED' - отвеченные,
    						// 'NO ANSWER' - пропущенные,
    						// 'BUSY' - занят,
    						// 'FAIL'- ошибка соединения).

    	    'calltype' => 'any',      		// тип звонка (any - любой,
						// 'IN' - входящие,
        					// 'OUT' - исходящие,
        					// 'LOCAL' - внутренние,
        					// 'TRANSIT' - транзит,
        					// 'SERVICE' - сервисные).

	    'points' => '12, 13'		// точки (any - получить информацию обо всех 
						// абонентах, или укажите абонентов, через
						// запятую).
        );
    
    

Получение списка точек (get-points)

Параметры:

    
	$post = array(
    	    'cell' => '8736',
    	    'method' => 'get-points',
        );
    
    

Получение списка каналов (get-trunks)

Параметры:

    
        $post = array(
    	    'cell' => '8736',
    	    'method' => 'get-trunks',
        );
    
    

Получение размера файла (get-filesize)

Параметры:

    
        $post = array(
    	    'cell' => '8736',
    	    'method' => 'get-filesize',

    	    'link' => 1234,			// id файла
        );
    
    

Получение файла (get-file)

Параметры:

    
        $post = array(
    	    'cell' => '8736',
    	    'method' => 'get-file',

    	    'link' => 1234,			// id файла
        );
    
    

Заказ обратного звонка (call-me)

Параметры:

    
        $post = array(
    	    'cell' => '8736',
    	    'method' => 'call-me',

    	    'src' => '201',			// Номер оператора
    	    'dst' => '89060728208',		// Номер клиента
	);
    
    

WebHook

Для того, чтобы получать информацию о звонках, произошедшем в вашем контракте, нужно, во-первых, подписаться на получение соответствующего типа событий. На данный момент для подписки доступно только событие call-finished, которое выполняется при завершении звонка.

Пример массива, который позволяет подписаться на событие:

    
	$post =  array(
		'cell' => 8736,
		'method' => 'subscribe',
		'url' =>  ‘https://omega.iptelefon.su/zeon/api-handler’, // ссылка, на которую будут отправляться данные
		'event' => ‘call-finished’ // тип события, на которое хотите подписаться
	);
    
    

Так же на событие ‘call-finished’ можно подписаться из меню настроек API виртуальной АТС Hive.




Просто введите URL вашей системы в соответствующее поле.



После получения запроса на подписку наш сервер начинает отправлять данные на указанный адрес.

Пример данных, которые посылает наш сервер на ваш url при событии call-finished:

    
	$post = array (
		'calldate' => '2017-05-03 09:41:53',
		'src' => 84957952929,
		'dst' => 00001111,
		'initiator' => 84957952929, // Дополнительное поле, показывающее номер, с которого поступил вызов
		'trunk' => 'Канал',
		'billsec' => 3, // Длительность вызова
		'disposition' => 'ANSWERED',
		'calltype' => 'IN',
		'link' => 1111111, // Уникальный идентификатор звонка
		'filename' => 'some-record.wav',
	);
    
    

На каждый запрос наш API ожидает возвращение строки ‘OK’. В случае трёх некорректных ответов подряд подписка отменяется.

Соединение по технологии WebSockets

Наш API даёт возможность отслеживать статус учётных записей на нашей АТС по протоколу WebSockets. Для этого сначала нужно установить соединение и подписаться на объект, состояние которого вы хотите отслеживать. Внимание! Для использования этого сервиса нужно связаться с нашей командой по адресу support@iptelefon.ru для авторизации вашего API-хэша.

Соединение можно устанавливать следующим JavaScript кодом:

    
        this.websocket_start = function() {
            if (self.wssInstance > 1)
                return;
            self.socket = new WebSocket('wss://hive.iptelefon.su:8080/');
            self.socket.onopen = function() {
                self.tryWsCreate = 0;
                self.hash = 'secret'; // ваш API хэш
                self.cell = '8736'; // ваш номер контракта
                self.numbers = [911, 922]; // массив номеров, статус которых вы хотите отслеживать
                var time = Math.floor(Date.now() / 1000).toString();
                time = time.slice(-3);
                var data_to_send = 'sid=API-' + self.secret + '&uid=' + self.cell + '0' + time + "&service=monitor&command=update&params=" + self.numbers.join('~');
                self.socket.send(data_to_send);
                return;
            };
 
            self.socket.onclose = function(e) {
                setTimeout(self.terminateWsAndCreate, 5000);
                if (self.tryWsCreate++ > 5) {
                    self.tryWsCreate = 0;
                    //self.show_error();
                }
                return;
            };
 
            this.terminateWsAndCreate = function() {
                self.socket = null;
                self.websocket_start();
                return;
            };
        }
    
    

При установлении WebSocket соединения с АТС происходит «подписка» на выбранный номер (номера). После этого на События, происходящие с этим номером на АТС, возвращаются в формате events = [{oid: "911", type: "4", state: "3", extra: ""}, {oid: "922", type: "4", state: "3", extra: ""}].

Где:

Oid – номер телефона, на который сделана подписка
Type – тип объекта (канал – 10, WS соединение - 6, учётная запись - 4)
State – состояние объекта (звонит – 5, принимает вызов – 4, не зарегистрирован – 3,зарегистрирован – 2)
Extra – дополнительное поле

После получение события по WS его можно обработать одним из методов.

Get-caller

Метод позволяющий узнать, кто в данный момент звонит на номер.

    
	$post =  array(
		'cell' => 8736,
		'method' => 'get-caller',
		'callee' =>  ‘00001111’, // 
	);
    
    

Get-callee

Метод позволяющий узнать, кому в данный момент звонит абонент.

Параметры:

    
	$post =  array(
		'cell' => 8736,
		'method' => 'get-callee',
		'caller' =>  ‘00001111’, // 
	);
    
    

Пример кода для обработки событий, получаемых по протоколу WebSocket:

    
 	$(document).ready(function() {
                this.websocket_start = function() {
 
                        if (self.wssInstance > 1)
                                return;
                        self.ws_url = 'wss://hive.iptelefon.su:8080/';
                        self.post_url = 'https://hive.iptelefon.su/hive/api/';
                        self.secret = 'secret'; //лучше вынести ваш хэш в отдельный файл, чтобы он не мог попасть в руки к третьим лицам
                        self.socket = new WebSocket(self.ws_url);
                        self.socket.onopen = function() {
                                self.tryWsCreate = 0;
                                self.sid = 'EXTERNAL-CONNECTION-secret'; // особый параметр для работы с веб-сокетом. Получается у нашей Технической Поддержки
                                self.cell = '8736'; // ваш номер контракта
                                self.numbers = ["0000712", 7778]; // массив номеров, статус которых вы хотите отслеживать
                                var time = Math.floor(Date.now() / 1000).toString();
                                time = time.slice(-3);
                                var data_to_send = 'sid=' + self.sid + '&uid=' + self.cell + '0' + time + '&service=monitor&command=update&params=' + self.numbers.join('~');
                                self.socket.send(data_to_send);
                                return;
                        };
 
                        self.api_query = function(data) {
                                data['hash'] = hex_md5($.param(data) + self.secret); //функция для работы подключается отдельно, например, отсюда: https://hive.iptelefon.su/hive/js/md5-min.js
                                $.ajax({
                                        type: "POST",
                                        url: self.post_url,
                                        data: data,
                                        success: function(msg) {
                                                return;
                                        },
                                        error: function(msg) {
                                                //self.show_error();
                                        }
                                });
                        };
 
                        self.socket.onclose = function(e) {
                                setTimeout(self.terminateWsAndCreate, 5000);
                                if (self.tryWsCreate++ > 5) { // пытаемся установить соединение 5 раз
                                        self.tryWsCreate = 0;
                                        //self.show_error();
                                }
                                return;
                        };
 
                        this.terminateWsAndCreate = function() {
                                self.socket = null;
                                self.websocket_start();
                                return;
                        };
 
 
 
 
                        self.socket.onmessage = function(e) {
                                eval(e.data);
                                if (typeof(events) == "undefined" || events.length == 0)
                                        return;
                                var ev = null;
                                for (var i in events) {
                                        if (events[i].oid !== '0') {
                                                ev = events[i];
                                                break;
                                        }
                                }
                                if (ev == null)
                                        return;
                                if (ev.state == '2')
                                        self.callObject = null;
                                if (self.callObject != null && ev.state != '5')
                                        return;
                                if (ev.state == '4') { // обработчик входящего вызова
                                        var request_data = {
                                                "cell": self.cell,
                                                "method": "get-caller",
                                                "callee": ev.oid
                                        };
                                        var caller = self.api_query(request_data);
                                        caller = caller['caller'];
                                };
                                if (ev.state == '5') { // обработчик исходящего вызова
                                        var request_data = {
                                                "cell": self.cell,
                                                "method": "get-callee",
                                                "caller": ev.oid
                                        };
                                        var callee = self.api_query(request_data);
                                        callee = callee['callee'];
                                };
                                return;
                        };
                };
 
                this.websocket_start();
        });
    
    

Готовый класс

Для вашего удобства мы подготовили PHP класс для работы с нашим API.

    
	<?php


	/**
	* api-client.php : zeOn
	* Copyright (c) 2012 - 2016 Oleg Shteinliht (fish9370@mail.ru),
	* Russian Federation, Moscow
	**/

	class api {
		var $cell;
		var $secret;
		var $url;

		var $curl;
		var $ctype;		/* content type */
		var $len;		/* content length */
		var $head;		/* http header */
		var $content;		/* content */

		var $result;		/* php array result */
		var $last_error;

		function api($cell, $secret, $url) {
			$this->cell = $cell;
			$this->secret = $secret;
			$this->url = $url;
			$this->curl = curl_init($url);
			curl_setopt($this->curl, CURLOPT_POST, true);
			curl_setopt($this->curl, CURLOPT_HEADER, true);
			curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, true);
		}

		function query($post) {
			$post['hash'] = md5(http_build_query($post) . $this->secret);
			curl_setopt($this->curl, CURLOPT_POSTFIELDS, http_build_query($post));	

			$response = curl_exec($this->curl);
			$this->ctype = curl_getinfo($this->curl, CURLINFO_CONTENT_TYPE);
			$this->head = substr($response, 0, curl_getinfo($this->curl, CURLINFO_HEADER_SIZE));
			$this->content = substr($response, curl_getinfo($this->curl, CURLINFO_HEADER_SIZE));
			$this->len = curl_getinfo($this->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD);

			switch ($this->ctype) {
				case 'application/json':
					$content = json_decode($this->content, true);

					if (isset($content['code']) && $content['code'] == 'fail') {
						$this->last_error = $content['text'];

						return FALSE;
					}
	
					$this->result = $content;
					return TRUE;

				case 'audio/wav':
				case 'image/tiff':
				case 'application/octet-stream':
					return TRUE;
			}
		
			return FALSE;
		}

		function close() {
			curl_close($this->curl);
		}

		function get_filename() {
			if (!preg_match("/^Content-disposition: .*?filename=(.*)$/m", $this->head, $match)) {
				$this->last_error = 'filename is not assigned';
				return FALSE;
			}

			$filename = trim($match[1]);

			if (strpos($filename, "..") !== FALSE) {
				$this->last_error = 'hack attempt';
				return FALSE;
			}

			return $filename;
		}

		function get_calls($start, $end, $limit = 0, $disposition = 'any', $calltype = 'any') {
			$post = array(
				'cell' => $this->cell,
				'method' => 'get-calls',
				'start' => $start,
				'end' => $end,
				'limit' => $limit,
				'disposition' => $disposition,
				'calltype' => $calltype
			);

			return $this->query($post);
		
		}

		function get_points($state = false) {
			$post = array(
				'cell' => $this->cell,
				'method' => 'get-points',
			);
		
			return $this->query($post);
		}

		function get_trunks($state = false) {
			$post = array(
				'cell' => $this->cell,
				'method' => 'get-trunks',
			);
		
			return $this->query($post);
		}

		function get_filesize($link) {
			$post = array(
				'cell' => $this->cell,
				'method' => 'get-filesize',
				'link' => $link
			);
		
			return $this->query($post);
		}

		function get_file($link, $path) {
			$post = array(
				'cell' => $this->cell,
				'method' => 'get-file',
				'link' => $link
			);

			if (empty($path)) {
				$this->last_error = 'empty path';
				return FALSE;
			}

			if (($ret = $this->query($post)) && ($filename = $this->get_filename())) {
				file_put_contents($path . '/' . $filename, $this->content);

				return TRUE;
			}

			return FALSE;
		}

		function set_subscription($url, $event){
			$post = array(
				'cell' => $this->cell,
            			'method' => 'subscribe',
				'event' => $event,
	            		'url' =>  $url,
			);
			return $this->query($post);
		}

		function get_callee($caller){
			$post = array(
				'cell' => $this->cell,
            			'method' => 'get-callee',
		    		'caller' => $caller,
			);
			return $this->query($post);
		}

		function get_caller($callee){
			$post = array(
				'cell' => $this->cell,
        	                'method' => 'get-caller',
			        'callee' => $callee,
			);
			return $this->query($post);
		}

	}

	?>
    
    

Подключите его в свой проект и используйте его методы.

Пример использования:

Текст заголовка
    

	<?php

		include "api-client.php";

		$api = new api('8736', 'secret', 'https://hive.iptelefon.su/hive/api/');
		if ($api->get_calls('2016-01-01', '2016-02-01')) {
    	    		print_r($api->result);
		} else
        		echo $api->last_error;

		if ($api->get_points()) {
    	    		print_r($api->result);
		} else
    	    		echo $api->last_error;

		if ($api->get_trunks()) {
    	    		print_r($api->result);
		} else
    	    		echo $api->last_error;

		if ($api->get_filesize('testfile')) {
    	    		print_r($api->result);
		} else
        		echo $api->last_error;

		if ($api->get_file('testfile', '/home/test')) {
        		printf("downloaded file %s\n", $api->get_filename());
		}

		if ($api->set_subscription('https://zeonpbx.ru', 'call-finished')) {
        		print_r($api->result);
		} else
    	 	   	echo $api->last_error;

		if ($api->get_caller('0000001')){
    	    		print_r($api->result);
		} else
    	    		echo $api->last_error;

		$api->close();

	?>