> Версия документа: 0.2.6

## HTTP-запросы, отправляемые данным API в сторону CRM-системы

В данном разделе приведён список событий, которые API может отправлять в CRM-систему.

Базовая часть URL для отправки запросов к API
http(s)://crm.example.com

Основной формат ответа на все события
Данное API ожидает ответ на все отправляемые события в следующем формате:

```json
{
      "resp_status": "<если успешно — значение 'ok', иначе — значение 'error'>",
      "error": "<если resp_status='error' — текст ошибки, иначе — пустоезначение>"
}
```

Для отдельных событий в ответе могут быть использованы дополнительные поля (они описаны в разделе соответствующего события).
Если CRM не ответит на событие или вернёт ошибку, можно (опционально) хранить событие в буфере в течение настраиваемого промежутка времени и периодически повторять его отправку.

### Общие параметры, присутствующие во всех событиях

Перечисленные ниже параметры присутствуют абсолютно во всех событиях, отправляемых API. 
В основном они не будут указаны в описании событий. Только параметры event и event_type будут указаны для каждого события, также некоторые параметры будут уазаны для событий, в контексте которых они имеют другое значение:

1. call_id — идентификатор вызова в Asterisk. У событий, относящихся к одному вызову, значение поля call_id будет одинаковым
2. event — имя события
3. event_type — общий тип события (никогда не зависит от направления вызова в отличие от имени события)
4. call_direction — изначальное направление вызова, может иметь значения "inbound", "outbound" и "internal"
5. direction — направление текущего этапа вызова, может иметь значения "inbound", "outbound" и "internal"
6. call_start_time — время начала вызова
7. call_cid_num — изначальный номер звонящего при поступлении вызова
8. call_callee_num — изначально вызванный номер при поступлении вызова
9. cid_num — номер звонящего на текущем этапе вызова
10. callee_num — вызванный номер на текущем этапе вызова

Дополнительно во всех событиях, связанных с входящими вызовами (call_direction=inbound), будет указан параметр did с DID-номером, на который поступил вызов (обычно он совпадает с call_callee_num, но может отличаться из-за особенностей некоторых провайдеров).

## Входящий вызов

### Начало входящего вызова

```http request
POST /calls/events
Content-Type: application/json

{
   "event": "inbound_start",
   "event_type": "call_start"
}
```

Входящий вызов может поступить на любое количество абонентов, – для каждого такого этапа вызова будут отправлены события "inbound_dial_start", "inbound_dial_end" и, в случае ответа, "inbound_dial_answer".

Формат ответа:
```json
{
   "resp_status": "<если успешно — значение 'ok', иначе — значение 'error'>",
   "error": "<если resp_status='error' — текст ошибки, иначе — пустое значение>",
   "to_ext": "<внутренний номер, на который нужно направить входящий вызов>"
}
```

Если параметр to_ext отсутствует или значением параметра to_ext является пустая строка или null, – входящий вызов будет обработан по обычному сценарию.

### Начало этапа входящего вызова (поступление входящего вызова на абонента)

Даже если входящий вызов будет направлен на внешний номер (например мобильный сотрудника), при этом всё равно будет
отправлено событие inbound_dial_start

```http request
POST /calls/events
Content-Type: application/json

{
   "event": "inbound_dial_start",
   "event_type": "dial_start",
   "dial_id": "<ID этапа вызова>",
   "from_queue": "<номер очереди, из которой пришёл вызов, или null>",
   "dial_start_time": "<время поступления вызова на номер callee_num>"
}
```

### Ответ на входящий вызов

```http request
POST /calls/events
Content-Type: application/json

{
   "event": "inbound_dial_answer",
   "event_type": "dial_answer",
   "dial_id": "<ID этапа вызова>",
   "from_queue": "<номер очереди, из которой пришёл вызов, или null>",
   "dial_start_time": "<время поступления вызова на номер callee_num>",
   "dial_answer_time": "<время ответа на вызов>",
   "wait_duration": "<время ожидания ответа>"
}
```

### Завершение этапа входящего вызова

```http request
POST /calls/events
Content-Type: application/json

{
   "event": "inbound_dial_end",
   "event_type": "dial_end",
   "dial_id": "<ID этапа вызова>",
   "from_queue": "<номер очереди, из которой пришёл вызов, или null>",
   "dial_start_time": "<время поступления вызова на номер callee_num>",
   "dial_answer_time": "<время ответа на вызов>",
   "dial_end_time": "<время завершения вызова>",
   "wait_duration": "<время ожидания ответа>",
   "talk_duration": "<время разговора>",
   "dial_status": "<статус вызова>"
}
```

Если абонент ответил на вызов, параметр "dial_status" будет иметь значение "ANSWER". 
Если параметр "dial_status" имеет любое другое значение, значит абонент не ответил на вызов.
Также, параметр "dial_answer_time" будет иметь значение null, если абонент не ответил на вызов.

### Завершение входящего вызова

Событие "inbound_end" отправляется в тот момент, когда все этапы данного входящего вызова завершены, а новые не могут
быть начаты из-за того, что все участники повесили трубку.

```http request
POST /calls/events
Content-Type: application/json

{
   "event": "inbound_end",
   "event_type": "call_end",
   "call_end_time": "<время завершения вызова>",
   "wait_duration": "<общее время ожидания ответа>",
   "talk_duration": "<общее время разговора>",
   "noanswer": "<1, если не было соединения ни с одиним абонентом>",
   "has_record": "<1, если для вызова есть запись>"
}
```

Параметр "noanswer" будет иметь значение 1, если в течение всего входящего вызова на него не ответил ни один абонент (если хотя бы один абонент ответил на вызов, параметр "noanswer" будет иметь значение 0).
Параметр "has_record" будет иметь значение 1, если для данного вызова была сделана запись (ссылка на запись будет в событии record_ready). 

## Исходящий вызов

### Начало исходящего вызова

```http request
POST /calls/events
Content-Type: application/json

{
   "event": "outbound_start",
   "event_type": "call_start"
}
```

### Начало этапа исходящего вызова

```http request
POST /calls/events
Content-Type: application/json

{
   "event": "outbound_dial_start",
   "event_type": "dial_start",
   "dial_id": "<ID этапа вызова>",
   "dial_start_time": "<время начала вызова>"
}
```

### Ответ на исходящий вызов

```http request
POST /calls/events
Content-Type: application/json

{
   "event": "outbound_dial_answer",
   "event_type": "dial_answer",
   "dial_id": "<ID этапа вызова>",
   "dial_start_time": "<время начала вызова>",
   "dial_answer_time": "<время ответа на вызов>",
   "wait_duration": "<время ожидания ответа>"
}
```

### Завершение этапа исходящего вызова

```http request
POST /calls/events
Content-Type: application/json

{
   "event": "outbound_dial_end",
   "event_type": "dial_end",
   "dial_id": "<ID этапа вызова>",
   "dial_start_time": "<время начала вызова>",
   "dial_answer_time": "<время ответа на вызов>",
   "dial_end_time": "<время завершения вызова>",
   "wait_duration": "<время ожидания ответа>",
   "talk_duration": "<время разговора>",
   "dial_status": "<статус вызова>"
}
```

Если вызванный номер ответил, параметр "dial_status" будет иметь значение "ANSWER". 
Если параметр "dial_status" имеет любое другое значение, значит вызванный номер не ответил на вызов.
Также, параметр "dial_answer_time" будет иметь значение null, если вызванный номер не ответил на вызов.

### Завершение исходящего вызова

Событие "outbound_end" отправляется в тот момент, когда все этапы данного исходящего вызова завершены, а новые не могут быть начаты из-за того, что все участники повесили трубку.

```http request
POST /calls/events
Content-Type: application/json

{
   "event": "outbound_end",
   "event_type": "call_end",
   "call_end_time": "<время завершения вызова>",
   "wait_duration": "<общее время ожидания ответа>",
   "talk_duration": "<общее время разговора>",
   "noanswer": "<1, если не было соединения ни с одиним абонентом>",
   "has_record": "<1, если для вызова есть запись>"
}
```

Параметр "noanswer" будет иметь значение 1, если в течение всего исходящего вызова на него не ответил ни один абонент (если хотя бы один абонент ответил на вызов, параметр "noanswer" будет иметь значение 0).
Параметр "has_record" будет иметь значение 1, если для данного вызова была сделана запись (ссылка на запись будет в
событии record_ready). 

## Внутренний вызов

### Начало внутреннего вызова

```http request
POST /calls/events
Content-Type: application/json

{
   "event": "internal_start",
   "event_type": "call_start"
}
```

### Начало этапа внутреннего вызова

```http request
POST /calls/events
Content-Type: application/json

{
   "event": "internal_dial_start",
   "event_type": "dial_start",
   "dial_id": "<ID этапа вызова>",
   "dial_start_time": "<время начала вызова>"
}
```

### Ответ на внутренний вызов

```http request
POST /calls/events
Content-Type: application/json

{
   "event": "internal_dial_answer",
   "event_type": "dial_answer",
   "dial_id": <ID этапа вызова>,
   "dial_start_time": <время начала вызова>,
   "dial_answer_time": <время ответа на вызов>,
   "wait_duration": <время ожидания ответа>
}
```

### Завершение этапа внутреннего вызова

```http request
POST /calls/events
Content-Type: application/json

{
   "event": "internal_dial_end",
   "event_type": "dial_end",
   "dial_id": <ID этапа вызова>,
   "dial_start_time": <время начала вызова>,
   "dial_answer_time": <время ответа на вызов>,
   "dial_end_time": <время завершения вызова>,
   "wait_duration": <время ожидания ответа>,
   "talk_duration": <время разговора>,
   "dial_status": <статус вызова>
}
```

Если вызванный номер ответил, параметр "dial_status" будет иметь значение "ANSWER". Если параметр "dial_status" имеет любое другое значение, значит вызванный номер не ответил на вызов.
Также, параметр "dial_answer_time" будет иметь значение null, если вызванный номер не ответил на вызов.

### Завершение внутреннего вызова

Событие "internal_end" отправляется в тот момент, когда все этапы данного внутреннего вызова завершены, а новые не могут быть начаты из-за того, что все участники повесили трубку.

```http request
POST /calls/events
Content-Type: application/json

{
   "event": "internal_end",
   "event_type": "call_end",
   "call_end_time": <время завершения вызова>,
   "wait_duration": <общее время ожидания ответа>,
   "talk_duration": <общее время разговора>,
   "noanswer": <1, если не было соединения ни с одиним абонентом>,
   "has_record": <1, если для вызова есть запись>
}
```

Параметр "noanswer" будет иметь значение 1, если в течение всего внутреннего вызова на него не ответил ни один абонент (если хотя бы один абонент ответил на вызов, параметр "noanswer" будет иметь значение 0).

Параметр "has_record" будет иметь значение 1, если для данного вызова была сделана запись (ссылка на запись будет в событии record_ready). События, не зависящие от направления вызова

### Вызов переведён

```http request
POST /calls/events
Content-Type: application/json

{
   "event": "transfer",
   "event_type": "transfer",
   "transfer_type": <"attended" или "blind">,
   "transfer_answered": <1, если в момент перевода адресат уже ответил>,
   "cid_num": <переведённый номер>,
   "callee_num": <номер адресата перевода>,
   "xfered_by_num": <номер переводящего>,
   "xfer_time": <время перевода>
}
```

Параметр "transfer_answered" будет иметь значение 1, если в момент совершения перевода адресат уже ответил на вызов.
В случае перевода вслепую (transfer_type=blind), "transfer_answered" всегда будет иметь значение 0.

Событие, следующее за данным событием зависит от типа перевода:

1. transfer_type=blind (перевод вслепую) - следующим должно идти событие inbound_dial_start (либо может идти сразу inbound_end, если адресат не ответил на вызов или вызов был переведён на несуществующий номер и не предусмотрено сценария обработки ошибок при переводе)
2. transfer_type=attended (управляемый перевод) - в данном случае переводящий уже совершил вызов, но то, что это часть управляемого перевода, становится понятно только в момент перевода, поэтому событие inbound_dial_start по данному вызову отправляется с другим call_id. Если на момент совершения перевода адресат уже ответил на вызов (transfer_answered=1) — inbound_dial_answer для соединения переводимого номера с адресатом отправляется прямо перед событием transfer.

После выполнения управляемого перевода (transfer_type=attended), вызов между переводящим и адресатом перевода сразу завершается. 
При завершении этого вызова, как обычно, отправляется событие с event_type=call_end, но в этом событии присутствует дополнительный параметр call_id_merged_to.
Значением call_id_merged_to является call_id переведённого вызова (т.е. Там будет такой же call_id, как в событии transfer, вызвавшем появление параметра call_id_merged_to).

## Запись вызова готова к скачиванию

```http request
POST /calls/events
Content-Type: application/json

{
   "event": "record_ready",
   "event_type": "record_ready",
   "recording_url": <ссылка на запись вызова>
}
```

В контексте данного события, параметры "cid_num", "callee_num" и "direction" (см. описание общих событий) имеют отношение к этапу вызова во время которого началась запись. HTTP-запросы, отправляемые CRM-системой в сторону API

Базовая часть URL для отправки запросов к API:
http(s)://pbx.example.com:5095

## Запрос на совершение вызова

```http request
POST /calls/place_call
Content-Type: application/json

{
   "call_first_num": "<номер, который нужно вызвать первым>",
   "connect_with_num": "<номер, который нужно вызвать, когда номер из call_first ответит>"
}
```

Формат ответа:
```json
{
   "resp_status": "<если успешно — значение 'ok', иначе — значение 'error'>",
   "error": "<если resp_status='error' — текст ошибки, иначе — пустое значение>"
}
```


## Запрос списка вызовов

GET /calls/list?from_date=<дата начала выборки>&to_date=<дата окончания выборки>&num=<номер>&max_calls=<максимальное_количество_вызовов>&offset=<смещение>

- from_date — если параметр не указан, будет произведена выборка за текущий день
- to_date — если параметр не указан, будет произведена выборка всех вызовов по текущее время.
- num — выбирать только звонки, в которых участвует указанный номер в качестве cid_num или callee_num.
- max_calls — максимальное количество вызовов в возвращаемом результате (если не указать или указать значение больше 10000, — будет использовано значение 10000)
- offset — смещение относительно начала выборки

> - параметры from_date и to_date должны быть в формате "%Y-%m-%d" или "%Y-%m-%d %H:%M:%S"
> - параметры max_calls и offset позволяют получать большие выборки с помощью последовательных запросов

Формат ответа:
```json
{
  "resp_status": "ok", 
   "format": [
		"call_date",
		"call_id",
		"cid_num",
		"callee_num",
		"did",
		"call_status",
		"ringing_duration",
		"talking_duration",
		"recording_url"
	],
	"calls": [
		[
			"<время начала вызова>",
			"<ID вызова в Asterisk>",
			"<номер звонящего>",
			"<вызванный номер>",
			"<городской номер, на который поступил вызов>",
			"<статус вызова>",
			"<длительность ожидания ответа>",
			"<длительность разговора>",
			"<ссылка на запись вызова>"
		]
	],
	"calls_count": "<количество звонков в выборке>",
	"max_calls": "<фактическое значение max_calls, использованное при выборке>",
	"offset": "<значение offset, использованное при выборке>"
}
```

> resp_status - если успешно — значение "ok", иначе — значение "error"