Описание сервиса
Общие сведения
Сервис предоставляет доступ к функционалу Sender посредством http(s) транспорта.
Формат запросов-ответов и url
Тестовый сервер (dev): https://api-dev.sender.mobi/ver/
Пререлизный сервер (rc): https://api-rc.sender.mobi/ver/
Боевой сервер (prod): https://api.sender.mobi/ver/
ver - версия используемого АПИ
Все запросы посылаются методом POST с content-type "application/json", в кодировке UTF-8. В теле запроса отправляется json-структура, в ответе возвращается также json.
В определенные моменты времени сервер присылает клиенту (в comet-соединение) пакет вида:
{
"cid": "<clientMsgId>",
"chatId":"<chatId>",
"model":{
"1":"xxx.xxx.xxx.xxx",
"2":"xxx.xxx.xxx.xxx"
}
"formId": "",
"robotId": "ip",
"companyId": "sender",
"type":"sys"
}
Тут поля обьекта model это порядковые номера (приоритет) ip-адресов для доступа к серверу. Если позиция "0" не занята, то в эту позицию следует поместить доменное имя. Иначе - помещаем его в конец списка. По этому списку осуществляем подключение к серверу. При получении любого невалидного ответа или сетевой ошибки переходим на следующий адрес.
Terminology:
developerID - ID выданный Сендером для индентификации Разработчика. Сохранияется в коде приложения;
developerKey - Секретный ключ выданный Сендером. Уникальный для каждого разработчика. Сохранияется в коде приложения;
UDID - Уникальный идентификатор устройства, подписанный разработчиком. Генерируется перед отправвкой на сервер;
masterKey - Уникальный идентификатор регистрации устройства в системе. Получается с сервера и сохраняется в настройках приложения;
Для генерации нужно использовать железный идентификатор устройства, например IMEI. Идентификатор устройства меняться не должен
UDID = HMAC-SHA1(Developer-Key, IMEI)
SHA1 длинной 160 символов
Вызывает клиент, если у него отсутсвует deviceKey или streaming закрывается ошибкой "3". Данный запрос не использует протокол форм.
POST /reg
{
"developerId":"1234",
"udid": "<udid>",
"pushToken":"<pushToken>",
"devType": "<DevType>",
"devModel": "<DevModel>"
"devOS":"<devOS>",
"versionOS":"<versionOS>",
"clientType":"<clientType>",
"clientVersion":"<clientVersion>",
"language":"<language>",
"companyId":"<companyId>"
}
Параметры "apns..." (только для IOS):
Ответ (синхронно)
{
"code": "0",
"deviceKey":"<deviceKey>",
"challenge": "<challenge>",
"mode": "<mode>"
}
mode может быть: 1) "full" - полная версия с п2п контактами, на текщий момент эквивалентна "sync_user_ct"="true" (т.е. слать контакты в синхронизации). 2) "restricted" - урезанная версия без п2п контактов, на текщий момент эквивалентна "sync_user_ct"="false" (т.е. не слать контакты в синхронизации).
Calculation masterKey
masterKey = HMAC-SHA256(developer_key, udid + device_key)
GET /[request]?udid=&token=
На любой запрос в случае передачи невалидного параметра token, сооединение будет закрыто с ответом:
{
"code": "1",
"challenge": "<challenge>"
}
challenge - рандомное значение из 64 символоd необходимое для рассчета параметра token по алгоритму:
token = HMAC-SHA256(masterKey, challenge)
Параметр token имеет ограниченное время жизни (2 часа). Новое значение challenge вернется при следующем поднятии соединения.
Посылает клиент если на клиенте изменился токен.
POST /token?udid=&token=
{
"token":"<Token>",
"apns":"<Apns>"
}
Параметр apns, (только для IOS), значения:
Ответ (синхронно)
{
"code": 0
}
POST /version_set?udid=&token=
{
"devType": "<DevType>",
"devModel": "<DevModel>",
"devManufact": "<devManufact>",
"devOS":"<devOS>",
"versionOS":"<versionOS>",
"clientType":"<clientType>",
"clientVersion":"<clientVersion>",
}
Ответ (синхронно)
{
"code": 0
}
POST /get_user_dev_info?udid=&token=
{
"userId": "<userId>"
}
Ответ (синхронно)
{
"code": 0,
"devs": [
{"sipLogin": "<sipLogin>"}
]
}
POST /get_sip_info?udid=&token=
{
"sipLogin": "<sipLogin>"
}
Ответ (синхронно)
{
"code": 0,
"userId": "<userId>"
}
Отправитель отправляет один раз в начале звонка пакет в send:
{
//позже уберем?
"formId": "", "robotId": "<robotId>", "companyId": "sender",
"from": "me", "chatId": "user+sender",
"class":".callRing.sender",
"model": {
"userId": "<toUserId>"
}
}
На все девайсы получателя приходит в comet и в push (в history это тоже приходит):
{
//позже уберем?
"from": "sender", "chatId": "user+sender",
"formId": "", "robotId": "<robotId>", "companyId": "sender",
"class": ".callState.sender",
"model": {
"state": "ring",
"userId": "<userId>",
"devId": "<devId>",
"sipLogin": "<sipLogin>",
"from_me": false,
"code": "no_devices"
},
"created": 1333333333,
"type": "sys"
}
state - может быть "ring" - гудок, "run" - разговор, "close" - завершен.
from_me - Boolean, если true - инициатор действия собственный девайс, false - чужой.
code - только для state="close", может быть "manual" когда человек отменил, "busy" - занят другим звонком, "no_devices" - если нет девайсов, есть и другие коды - при ошибках.
Параметры devId и sipLogin могут отсутствовать при state="close".
Когда получатель поднимает звонок sip он отправляет в send:
{
//позже уберем?
"formId": "", "robotId": "<robotId>", "companyId": "sender",
"from": "me", "chatId": "user+sender",
"class": ".callRun.sender",
"model": {
"userId": "<fromUserId>",
"devId": "<fromDevId>"
}
}
И вызывающему девайсу отпарвителя и всем остальным девайсам получателя приходит в comet .callState.sender c state="run". И отправитель должен начать sip звонок.
Когда звонок отменен или завершен, то нужно послать в send:
{
//позже уберем?
"formId": "", "robotId": "<robotId>", "companyId": "sender",
"from": "me", "chatId": "user+sender",
"class": ".callClose.sender",
"model": {
"userId": "<userId>",
"devId": "<devId>",
"code": "<code>"
}
}
devId - необязательный только для отправителя только тогда когда получатель ничего не ответил ему.
code - необязательный, разрешены следующие: "manual" - когда человек отменил, "busy" - занят другим звонком, если не указан то используется "manual".
И всем девайсам получателя и отправител приходит в comet .callState.sender c state="close".
Послать комнаду получения контакт форм компаний после авторизации.
POST /get_companies_cf?udid=&token=
{
}
Ответ (синхронно)
{
"code": 0,
"noDefaultCompanies":[
"<companyUserId1>", "<companyUserId2>" //...
],
"defaultView": {
//...
}
}
noDefaultCompanies - список UserId компаний у которых не дефалтовая форма контакта.
defaultView - фмл дефалтовой карточки, она также может прийти позже асинхроно через обычную форму контакта с CompanyId="!". В ней использется FML {{!meta.!user.<Parameter>}} с помощью которых подставлется данные компании.
После чего асинхронно приходят какрточки компаний у которых не дефалтовая форма контакта. У карточек контактов FormId="contact", RobotId="contact".
Запрос:
POST /send?udid=&token=
Тело запроса:
{
"fs": [
{
...
}
]
}
в массиве fs передеются обычные асинхронные формы. Если по отправленной форме нужно получить procId и серверное время (time), то в корень json-представления этой формы добавляем уникальный идентификатор cid, который будет получен в ответе
Ответ 200 OK
{
"cr": [
{
"cid": "<clientMsgId>",
"packetId": "<serverMsgId - packetId>",
"time": <time>
}
],
"code": 0
}
Алгоритм работы с очередью и пакетной отправки

Запрос:
POST /comet?udid=&token=&ac=<=&ln=
Тело запроса:
{
"meta": {
"net": "wifi",
"ci": "<chatId>"
},
"lbi": "<lastBatсhId>",
"size": <size>,
"ref": "<ref>"
}
ac - (обязательно), get параметр, идентифкатор текущего чата.
lt - (опционально), get параметр, географическая широта latitude в градусах, десятичный разделитель точка ".".
ln - (опционально), get параметр, географическая долгота longitude в градусах, десятичный разделитель точка ".".
lbi (обязательно), lastBatchId, строка - это bi (batchId), полученный в предыдущем ответе. Ответ на запрос приходит при наличии на сервере сообщений или через 5 минут приходит пустой.
size - (опционально), целое, ожидаемый максимальный размер пакета, если не указан то равен 50.
ref - (опционально), строка, референс пуша, который инициировал поднятие.
Ответ 200 OK
{
"bi": "<batchId>",
"fs": [
{
...
}
],
"code": 0
}
Если после ответа bi нет, в следующем запросе lbi не передается. Если lbi не вернуть на сервер, он повторит отправку сообщений, которые были в этом пакете
При получении формы с сервера клиент оповещает о их получении в зависимости от значения поля model.state. Возможные значения и действия по ним:
Текстовое сообщение представляет собой упрощённую "невидимую" форму вида:
{
"model":
{
"text":"<text of mesage>",
"key":"<key>"
},
"companyId":"sender",
"cid":"<cid>",
"formId":"text",
"robotId":"routerobot",
"chatId":"<chatId>"
}
Тут поле text содержит текст сообщения
Поле key содержит 5 последних символов публичного ключа получателя, которым было зашифровано сообщения (только для шифрованных сообщений)
Поля fromName и fromPhoto опциональны, если они присутствуют, то имя и иконка отправителя в чате берутся из этих полей а не по fromId
Поле chatId содержит id чата
При получении текстовое сообщение представляет собой форму:
{
"model":
{
"text":"<text of mesage>",
"encrypted":true,
"fromName":<users name>,
"fromPhoto":<users avatar path>
},
"companyId":"sender",
"cid":"<cid>",
"formId":"text",
"robotId":"routerobot",
"chatId":"<chatId>",
"from":"<userId>",
"type":"msg"
}
Тут поле text содержит текст сообщения
Поле encrypted (опционально) показывает зашифровано ли сообщение
Поле chatId содержит id чата
Поле from содержит userId отправителя
Сохранение, обновление и получение информации о себе
Сохранение, обновление. Если поле не передается, его не изменяем. Чтобы удалить значение - передаем поле с пустым значением.
POST /selfinfo_set?udid=&token=
{
"name": "<UserName>",
"photo": "<photoUrl>",
"address": "<address>",
"description": "<Description>",
"btcAddr": "<address for receive btc payments>",
"msgKey": "<public key to encrypt messages>"
}
Ответ (синхронно)
{
"code": 0
}
Получение:
POST /selfinfo_get?udid=&token=
{
}
Ответ (синхронно)
{
"selfInfo": {
"name": "<UserName>",
"photo": "<photoUrl>",
"address": "<address>",
"description": "<Description>",
"btcAddr": "<address for receive btc payments>",
"msgKey": "<public key to encrypt messages>",
"companies": [
"<companyId>",
...
],
"contacts": [
{
"type":"phone",
"value":"38093432334",
"valueRaw":"093 432334"
},
...
],
"code": 0
}
}
Получение информации о пользователе.
POST /get_user_info?udid=&token=
{
"userId": "<userId>",
"fields": ["<field>"]
}
Ответ 200 OK
{
"user": {
"name": "<UserName>",
"photo": "<photoUrl>",
"description": "<Description>",
"isCompany":"<isCompany>",
"contacts": [
{
"type":"phone",
"value":"38093432334"
},
...
]
}
"code": 0
}
fields - массив полей, которые необходимо вернуть. Пример fields:["name"]. Если не указан, возвращаются все.
Получение списка операторов и ролей компании
POST /get_operators
{
"companyId": "<companyId>"
}
Ответ 200 OK
{
"operators": [
{
"userId":"<userId>",
"roleId":"<roleId>",
"name": "<UserName>",
"photo": "<photoUrl>"
}
],
"roles":[
{
"roleId":"<roleId>",
"name": "<RoleName>"
}
],
"code": 0
}
Получение списка операторов компании
POST /get_company_operators
{
"companyId": "<companyId>"
}
Ответ 200 OK
{
"operators": ["<userId>"],
"code": 0
}
Запрос:
POST /history?udid=&token=
Тело запроса:
{
"pos":<pos>,
"size":<size>,
"chatId":"<chatId>"
}
pos - с какой позиции получать сообщения, 0 - с начала, n - c n-го сообщения
size - количество возвращаемых сообщений
Ответ 200 OK
{
"msgs": [<msgs>],
"code": 0
}
SendBar представляет собой набор элементов управления специфичный для чата с данной компанией.
Для всех чатов кроме p2p чата с компанией у которой явно установлен sendBar используется sendBar компании Sender";
Представляет собой json-структуру вида:
{
"textColor": "#000000",
"items": [
{
"id": "1",
"icon": "https://s.sender.mobi/bars/plus.png",
"actions": [
{
"oper": "reload",
"_0": [
2,
3,
4,
5,
8,
6,
7
],
"_1": [
9,
10,
11,
12,
13,
16,
17,
18
]
}
]
},
{
"id": "2",
"icon": "https://s.sender.mobi/bars/cancel.png",
"actions": [
{
"oper": "reload",
"_0": [
1,
3,
4,
5,
8,
6,
7
]
}
]
},
{
"id": "3",
"icon": "https://s.sender.mobi/bars/twitch.png",
"actions": [
{
"oper": "sendMedia",
"type": "twitch"
}
]
},
{
"id": "4",
"icon": "https://s.sender.mobi/bars/geo2.png",
"actions": [
{
"oper": "sendMedia",
"type": "location"
}
]
},
{
"id": "5",
"icon": "https://s.sender.mobi/bars/text.png",
"actions": [
{
"oper": "sendMsg",
"expand": false
},
{
"oper": "reload",
"_0": [
1,
5,
7,
8
]
}
]
},
{
"id": "6",
"icon": "https://s.sender.mobi/bars/camera.png",
"actions": [
{
"oper": "sendMedia",
"type": "photo"
}
]
},
{
"id": "7",
"icon": "https://s.sender.mobi/bars/smile.png",
"actions": [
{
"oper": "sendMedia",
"type": "smile"
}
]
},
{
"id": "8",
"icon": "https://s.sender.mobi/bars/voice.png",
"actions": [
{
"oper": "sendMedia",
"type": "voice"
}
]
},
{
"id": "9",
"icon": "https://s.sender.mobi/bars/add_user.png",
"name": {
"ru": "Добавить",
"en": "Add user"
},
"actions": [
{
"oper": "addUser"
}
]
},
{
"id": "10",
"icon": "https://s.sender.mobi/bars/stickers.png",
"name": {
"ru": "Стикер",
"en": "Sticker"
},
"actions": [
{
"oper": "sendMedia",
"type": "sticker"
}
]
},
{
"id": "11",
"icon": "https://s.sender.mobi/bars/attach.png",
"name": {
"ru": "Файл",
"en": "Send file"
},
"actions": [
{
"oper": "sendMedia",
"type": "file"
}
]
},
{
"id": "12",
"icon": "https://s.sender.mobi/bars/video.png",
"name": {
"ru": "Видео",
"en": "Send video"
},
"actions": [
{
"oper": "sendMedia",
"type": "video"
}
]
},
{
"id": "13",
"icon": "https://s.sender.mobi/bars/cards.png",
"name": {
"ru": "Деньги",
"en": "Money"
},
"actions": [
{
"oper": "reload",
"_1": [
14,
15
]
}
]
},
{
"id": "14",
"icon": "https://s.sender.mobi/bars/send.png",
"name": {
"ru": "Отправить",
"en": "Send"
},
"actions": [
{
"oper": "callRobot",
"class": ".sendMoney.sender"
}
]
},
{
"id": "15",
"icon": "https://s.sender.mobi/bars/top_up.png",
"name": {
"ru": "Пополнить",
"en": "Fill phone"
},
"actions": [
{
"oper": "callRobot",
"class": ".payMobile.sender"
}
]
},
{
"id": "16",
"icon": "https://s.sender.mobi/bars/lock_open.png",
"icon2": "https://s.sender.mobi/bars/lock_closed.png",
"name": {
"ru": "Шифрование",
"en": "Encryption"
},
"actions": [
{
"oper": "switchCrypto"
}
]
},
{
"id": "17",
"icon": "https://s.sender.mobi/bars/vibro.png",
"name": {
"ru": "Вибро",
"en": "Vibro"
},
"actions": [
{
"oper": "sendMedia",
"type": "vibro"
}
]
},
{
"id": "18",
"icon": "https://s.sender.mobi/bars/games.png",
"name": {
"ru": "Игры",
"en": "Play"
},
"actions": [
{
"oper": "reload",
"_1": [
19,
20,
21
]
}
]
},
{
"id": "19",
"icon": "https://s.sender.mobi/bars/tic-tac.png",
"name": {
"ru": "Крестики-нолики",
"en": "Tic Tac Toe"
},
"actions": [
{
"oper": "callRobot",
"class": ".ticTacToe.sender"
}
]
},
{
"id": "20",
"icon": "https://s.sender.mobi/bars/vinni.png",
"name": {
"ru": "Винни Пух",
"en": "Winny Puh"
},
"actions": [
{
"oper": "callRobot",
"class": ".winnieThePoohHoney.sender"
}
]
},
{
"id": "21",
"icon": "https://s.sender.mobi/bars/chess.png",
"name": {
"ru": "Шахматы",
"en": "Chess"
},
"actions": [
{
"oper": "callRobot",
"class": ".chess.sender"
}
]
}
],
"init": {
"_0": [
1,
3,
4,
5,
8,
6,
7
]
}
}
textColor - цвет текста подписей к кнопкам
name - подпись на кнопке
id - идентификатор элемента бара (для построения уровней)
icon - изображение на кнопке в нормальном состоянии
icon2 - изображение на кнопке во "включенном" состоянии (опционально)
actions - действия по нажатию
Бар строится в 2 уровня "0" и "1". Уровень "0" всегда видимый, "1" - может появиться при активации одного из элементов бара.
Построение начинается с заполнения уровней элементами согласно id перечисленных в соответствующем массиве элемента "init".
Любой из элементов может содержать в списке actions элемент с "oper":"reload". Action этого вида требует перестроения уровней, аналогично init.
Остальные actions (если они есть) выполняются поле reload. Если в init или reload состав уровня не описан, он очищается.
SendBar является опциональным свойством любого контакта компании.
Динамически создаваемые элементы интерфейса приложения (в т.ч. элементы fml-форм) при их актвации пользователем могут инициировать действия, описанные c помощью actions-атрибута:
Значением атрибута actions является массив обьектов, которые описывают действия, выполняемые в порядке следования в массиве.
Каждый обьект одержит обязательное поле: oper - определяющее выполняемую операцию, обязательное поле. Оста
Выполнить вызов внешнего сервера с параметрами (опционально), введёнными в фроме. При ответе сервера форма с содержимым ответа отправляется обычным способом
Пример:
{
"actions":
[
{
"oper":"extCall",
"url":"<url to external get request>",
"form_data": true
}
]
}
form_data - признак, следует ли отправлять в запросе поля формы. Поля отправяляются как get-параметры в формате <имя поля>=<значение>&...
Отправить пользователя в указанный интерфейс приложения. Обязательным атрибутом является "to", который принимает значения:
contacts|dialogs|profile|settings
В случае, если action описан в fml-форме, она должна быть отправлена на сервер перед переходом
Пример:
{
"actions":
[
{
"oper":"goTo",
"to":"<to>"
}
]
}
Возможные значения to
Добавить пользователя в текущий чат: открыть диалог выбора пользователя и по результату добавить выбранного (выбранных)
Если текущий чат p2p - будет создан новый, групповой чат
Пример:
{
"actions":
[
{
"oper":"addUser"
}
]
}
В поле "link" передается веб ссылка, начиная с http/https, поле обязательно. Открываем стандартный диалог выбора приложений для открытия ссылки, если таковых несколько. Если одно, открываем напрямую, если отсутствует уведомляем об отсутствии.
Пример:
{ "actions" : [ { "oper":"viewLink","link":"<link>" } ] }
Открыть окно ввода текста и введённый текст отправить сообщением в текущий чат
Пример:
{
"actions":
[
{
"oper":"sendMsg"
}
]
}
Открыть окно выбора медиа-контента (cпецифическое для типа контента и платформы) и выбранный контент отправить в текущий чат.
Обязательное поле type определяет тип контента. Варианты: sticker, file, photo, video, location
Пример:
{
"actions":
[
{
"oper":"sendMedia",
"type":"<type>"
}
]
}
При активации элемента с этим oper, показываем диалог сканирования, обращаемся к ридеру, при успешном сканировании строку к номером карты помещаем в поле "card" json-структуры, которую отправляем на серврер как model формы. Остальные ранее введённые данные этой формы также отправляются в этой структуре аналогично обычному submit формы.
Пример:
{
"actions":
[
{
"oper":"scanCard"
}
]
}
В поле "phone" передается телефон в международном формате, без плюса, поле обязательно. Открываем стандартный диалог телефонного вызова с этим номером
Пример:
{
"actions":
[
{
"oper":"callPhone",
"phone":"380501234567"
}
]
}
Вызывается робот в текущем чате (чате в котором форма находится).
В поле "class" передается класс робота который вызывается, поле обязательно.
Если авзывается из формы, при нажатии в model посылаются все те же элементы что и при нажатии на обычную кнопку этой формы.
Пример:
{
"actions":
[
{
"oper":"callRobot",
"class":"<robotClass>",
"data":
{
"name":"value"
}
}
]
}
Данные из обьекта "data" передаются в model вместе с данными формы. Если имена полей совпадают с именами полей в форме данные из "data" считаются более приоритетными
При нажатии клиент-приложение должно послать в этот чат обычный fsubmit запрос:
POST /fsubmit
{
"sid": "<sid>",
"chatId": "<chatId>",
"model": {},
"class": "<robotClass>"
}
В поле "userId" передается UserId пользователя или компании в p2p чат с которым нужно перейти, поле обязательно.
В поле "class" передается класс робота который вызывается, поле обязательно.
При нажатии в model посылаются все те же элементы что и при нажатии на обычную кнопку.
Пример:
{
"actions":
[
{
"oper": "callRobotInP2PChat",
"userId": "<userId>",
"class": "<robotClass>"
}
]
}
При нажатии клиент-приложение должно по найти/создать p2p чат и перейти в него, и послать в этот чат обычный fsubmit запрос:
POST /fsubmit
{
"sid": "<sid>",
"chatId": "<chatId>",
"model": {},
"class": "<robotClass>"
}
В поле "userId" передается UserId пользователя или компании в p2p чат с которым нужно перейти, поле обязательно.
Пример:
{
"actions":
[
{
"oper": "startP2PChat",
"userId": "<userId>"
}
]
}
При выборе элемента в поле action которого указан этот oper нужно открыть нативный диалог выбора пользователей из списка контактов.
В диалоге отображаются только зарегистрированные пользователи при "reg":true иначе - все пользователи.
При выборе конкретного пользователя его номер телефона помещается в поле формы, имя которого задано в атрибуте "to".
Если "autosubmit":true форма отправляется на сервер сразу после того, как клиент сделал выбор в списке контактов, иначе - после выбора форма доступна для работы и отправки на сервер обычным способом (кнопкой в форме)
Например:
{
"actions":
[
{
"oper": "selectUser",
"reg": true,
"to": "<field name>",
"autosubmit":true
}
]
}
При выборе элемента в поле action которого указан этот oper нужно скрыть элементы, name которых указаны в массиве "hide", и показать элементы, name которых указаны в массиве "show". Т.е. первой группе должен быть назначен "state":"gone" а второй - "state":"visible" выполнена перерисовка формы
{
"actions":
[
{
"oper": "switchView",
"hide":
[
elem1, elem2
],
"show":
[
elem3, elem4
]
}
]
}
При выборе элемента в поле action которого указан этот oper нужно открыть окно с картой (google maps), при выборе точки на карте значение поля val должно быть равно занчению широты и долготы с разделителем ";" а поле title должно быть равно адресу выбранной точки.
{
"actions":
[
{
"oper": "coords"
}
]
}
При выборе элемента в поле action которого указан этот oper нужно вызвать окно сканирования qr-кода и отсканированный результат отправить роботу, указанному в поле "class". model отправляемой формы должна содержать результат распознавания кода в поле "qr". Форму результата отправляем в чат указанный в поле "chatId". Например:
{
"actions":
[
{
"oper": "qrScan",
"class":"<robotClass>",
"chatId":"<chatId>"
}
]
}
В результает отправляем форму:
{
"sid": "<sid>",
"chatId": "<chatId>",
"model": {
"qr":"<value>"
},
"class": "<robotClass>"
}
Если для клиента есть сообщения, а он не вычитывает их, сервер может отправить клиенту push-сообщение по системному каналу, в зависимости от платформы клиента
Также сервер может спросить клиента в онлайне он или нет.
Push-сообщение представляет собой json-обьект вида:
{
"status": "wake_up",
"online_key": "<key>",
"ref":"<ref>"
}
Оба поля опциональны.
При получении "status":"wake_up" нужно поднять comet-канал для получения сообщений. "" передавать в коммет
При получении "online_key" нужно послать синхронный запрос вида:
POST /online?udid=&token=<token>&online_key=<key>&ref=
где - значение поля "online_key" в push-сообщении
В случае, если при получении/обработке ответа/сообщения с сервера произошла ошибка, то клиентское приложение шлёт на сервер форму:
{
"fs":
[
{
"cid": "<clientMsgId>",
"chatId":"<chatId>",
"model":{
"time":1223456,
"net":"<type of connection>",
"get":"< get request>",
"post":"<post request>",
"data":"<crash data>"
},
"formId": "",
"robotId": "crash",
"companyId": "sender"
}
]
}
где:
type of connection - тип соединения: wifi или mob
Вызов "взбодрить" в чате с параметром type.
type - один из: kickass fail lol omg win wtf cool hurray thanks
type:kickass - по умолчанию
POST /send?udid=&token=
{
"fs":
[
{
"cid": "<clientMsgId>",
"chatId":"<chatId>",
"model":{"type":"<type>"},
"formId": "",
"robotId": "alert",
"companyId": "sender"
}
]
}
Ответ 200 OK
{
"cr": [
{
"cid": "<clientMsgId>",
"packetId": "<serverMsgId - packetId>",
"time": <time>
}
],
"code": 0
}
Ответ (в comet)
{
"fs":
[
{
"model": {
"state":"alert"
},
"chatId": "<chatId>",
"from": "<userId>",
"formId": "<type>",
"robotId": "alert",
"companyId": "sender",
"view": "<fml>",
"type":"fml"
}
]
}
Для отправки шифрованного сообщения получателю должны быть соблюдены следующие условия:
Алгоритм зашифровывания:
Алгоритм расшифровывания:
При возникновении ошибки расшифровки считать сообщение не шифрованным и отображать "как есть"
При возникновении ошибки зашифровывания выводить сообщение пользователю и не отправлять сообщение
Загрузка файлов/изображений.
POST /upload?udid=<UDID>&token=<Token>&filename=<FileName>&filetype=<FileType>
BODY содержит загружаемый файл в бинарном формате. Максимальный размер файла 104857600 байт.
{
"url":"<URL>",
"code":0
}
FileName, FileType, URL - формат значений не определен.
Для загрузки картинок с созданием превью. Клиент-приложение это делает самостоятельно.
Поддерживаемые форматы: jpg, gif, png.
Если картинка большая - то можно запрещать посылать ее как картинику, только как файл (для web - не больше 5 MB).
Превью картинки: Конвертировать в jpg с коэффициентом сжатия 0.6, квадрат 400х400, если оригинальная картинка не квадратная - то из нее берется центральный квадрат. Альфа-канал заполнять белым цветом. Для гиф брать первый кадр (или если это невозможно то картинку-заглушку).
Полная картинка: 1) Для gif - оригинальный gif файл. 2) Для других форматов - конвертировать в jpg с коэффициентом сжатия 0.6, если большая из сторон превышает 1600 - сжимать пропорционально чтобы это сторона стала 1600, если не превышает - то размеры картинки оставлять оригинальными. Альфа-канал заполнять белым цветом.
Для загрузки аватаров пользователей.
Будет делать клиент-приложение, скоро будет согласование.
jpg размер 800x800. jpg размер 120x120.
Будет делать клиент-приложение, скоро будет согласование.
jpg размер 120x120.
Активация/деактивация полной версии сендера. После изменения версии необходимо выполнить повторную синхронизацию контактов. Подробнее в разделе Sync Request.
POST /full_version
{
"activate":"true|false"
}
Ответ
{
"sync_user_ct":"true|false"
}
sync_user_ct - синхронизировать или нет свою контактную книгу
Получить текущий чат.
Отправляет клиент в чат с Sender-oм.
POST /send в fs:
{
"chatId": "user+sender",
"model": {"companyId":"privat24"},
"companyId": "sender",
"robotId": "getCurrentChat",
"formId": ""
}
model.companyId - для какой компании выполняется, пока разрешено только "privat24" только
Ответ (синхронно)
Ответ (асинхронно)
{
"packetId": "<packetId>",
"linkId": "<packetId>",
"chatId": "user+sender",
"model": {
"chatId":"<chatId>"
},
"companyId": "sender",
"robotId": "getCurrentChat",
"formId": ""
}
model.chatId - текущий чат
Поиск компаний в глобальной книге
Отправляет клиент при вводе более 2ух символов в поисковой строке контактной книги
POST /global_search
{
"t":"Киевс"
}
t - введенный текст
Ответ (синхронно)
{
"code":0,
"cts"[
{
"userId": "<userId>",
"name": "<name>",
"description": "<description>",
"photo": "<photo>",
"isCompany": true
}
]
}
Поиск, обновление global_search.
Отправляет клиент при вводе более 2ух символов в поисковой строке контактной книги. Клиентам нужно экономить кол-во запросов, т.е. отправлять не по символьно - а через 1-2 секунды когда человек перестал печатать.
POST /search
{
"t":"Киевс"
}
t - введенный текст
Ответ (синхронно)
{
"code": 0,
"list": [
{
"type": "contact",
"userId": "<userId>",
"name": "<name>",
"description": "<description>",
"photo": "<photo>",
"isCompany": true
},
{
"type": "contact",
"userId": "<userId>",
"name": "<name>",
"description": "<description>",
"photo": "<photo>",
"isCompany": true,
"actions": [
{
"oper": "callRobotInP2PChat",
"userId": "<robotUserId>",
"name": "<robotName>",
"photo": "<robotPhoto>",
"class": "<robotClass>",
"data":{
"param1": "value1",
"param2": {"key2":"value2"},
"param3": [true, false, 1, -1.2, [], {}, {"q":"aaa"}]
}
}
]
}
]
}
userId, name, description, photo, isCompany - в этих полях приходят данные контакта.
action - необязательный параметр, массив, в котором приходят экшены.
action.oper - "callRobotInP2PChat" как и в action вызов робота в п2п чате.
action.photo, action.name - фото и подпись экшена.
action.userId - в какой чат переходить, сделано так для совместимости с action callRobotInP2PChat.
action.data - необязательный параметр, объект, если есть то это параметры которые нужно посылать в model при запуске робота.
Подтверждение доставки сообщения GET /deliv?udid=&token=&chatId=&packetId=
Ответ 200 OK
{
"code": 0
}
Оповещение о добавлении пользователя в чат.
Ответ (асинхронно)
{
"linkId": "<packetId>",
"packetId": "<packetId>",
"from": "sender",
"created": 1422312682124,
"chatId": "sender",
"companyId": "sender",
"robotId": "addChat",
"formId": "",
"class":".addChat.sender",
"type":"sys",
"model": {
"chatId": "<UpdatedChatId>",
"actionUser": {
"userId": "<userId>"
},
"users": [
{
"userId": "<userId>",
"role":"<role>",
"name":"<userName>"
}
...
],
"chatInfo": {
"chatId": "<UpdatedChatId>",
"chatName": "<ChatName>",
"chatDesc": "<ChatDescription>",
"chatPhoto": "<PhotoURL>",
"p2p": "<Boolean(true/false)>",
"companyId": "<companyId>",
"type":"<type>",
"members": [
{
"userId": "<userId>",
"role":"<role>"
}
...
]
},
"contactsInfo": [
{
"contactId": "<contactId>",
"userId": "<userId>",
"isOwn": "true",
"name": "<name>",
"description": "<description>",
"photo": "<photo>",
"isCompany": "<isCompany>",
"contactItemList": [{
"value": "<value>",
"valueRaw": "<valueRaw>",
"type": "<type>"
}]
},
...
]
}
}
actionUser - инициатор действия.
contactsInfo - полная информация по всем участникам чата, которые отсутсвуют у получателя на момент после добавления
model.chatId - chatId изменяемого чата
chatInfo - (опционально) передаётся только юзеру, которого добавили в чат.
userId - userId пользователя или значение "me".
Оповещение о удалении участников из чата.
Получают все пользователи чата, которые участвуют в чате, в том числе и удаляемые.
Ответ (асинхронно)
{
"linkId": "<packetId>",
"packetId": "<packetId>",
"chatId": "sender",
"from": "sender",
"created": 1422312682124,
"companyId": "sender",
"robotId": "delChat",
"formId": "",
"class": ".delChat.sender",
"type":"sys",
"model": {
"chatId": "<UpdatedChatId>",
"actionUser": {"userId":"<userId_or_me>"},
"users": [
{
"userId": "<userId>",
"role":"<role>",
"name":"<userName>"
}
...
]
}
}
actionUser.id - инициатор действия, может быть userId или "me"(когда инциатором являестя пользователь который и получил этот пакет)
users - список пользователей которые были удалены.
userId - userId пользователя или значение "me".
На клиенте этот пакет можно преобразовать в сообщение типа: "Пользователь(Вы) удалил из чата (Вас и) Пользовтеля2, Пользователя 3".
Оповещение о выходе из чата пользователя.
Получают все пользователи чата, которые участвуют в чате, в том числе и выходящий.
Ответ (асинхронно)
{
"linkId": "<packetId>",
"packetId": "<packetId>",
"chatId": "sender",
"from": "sender",
"created": 1422312682124,
"companyId": "sender",
"robotId": "leaveChat",
"formId": "",
"class": ".leaveChat.sender",
"type":"sys",
"model": {
"chatId": "<UpdatedChatId>",
"actionUser":
{
"userId":"<userId_or_me>",
"role":"<role>",
"name":"<userName>"
}
},
}
actionUser.userId - инициатор действия, может быть userId или "me"(когда инциатором являестя пользователь который и получил этот пакет)
На клиенте этот пакет можно преобразовать в сообщение типа: "Пользователь(Вы) вышел(вышли) из чата".
Предложение: после получения этого пакета - обновленный список участников нужно получить по info.chatrobot.sender - так сделано из-за возможной гонки пакетов о изменении участников чата. Этот пакет не приходит для п2п чата - для п2п чата придет второму собеседнику сразу сообщение (меньше отвлекающих сообщений, меньше трафика).
Получение бара.
POST /get_bar?udid=&token=
{
"barId": "<barId>"
}
Ответ 200 OK
{
"bar": {},
"code": 0
}
Для определённых клиентов на сервер отправляем аггрегированные данные о пользовательской активности (нажатия кнопок, переходы между экранами и т.п.). Данные следует отправлять не чаще чем раз в 10 минут.
POST /send в fs:
{
"chatId": "user+sender",
"model": {
"type":"<тип устройства, аналогично запросу reg>",
"model":"<модель устройства, аналогично запросу reg>",
"ver":"<версия клиентстого приложения, аналогично запросу reg>",
"udid":<UDID>,
"events":[
<массив json структур, представляющих собой события пользовательского интерфейса>
]
},
"companyId": "sender",
"robotId": "uiMonitoring",
"formId": ""
}
Открытие websocket соединения
ws://URL/websocket
Для начала работы сессии необходимо отправить пакет:
{
"class": "wsSession",
"model":{ "udid":"<udid>", "token":"<token>"}
}
Ответ в случае устаревшего токена:
{
"class": "wsChallenge",
"model":{ "challenge":"<challenge>"}
}
Список активных диалогов поддержки (приходит в вебсокете)
{
"class":".oDlgs.sender",
"model":{
"dlgs":[{
"chatId": "<UpdatedChatId>",
"companyId":"<companyId>",
"created":<created>,
"members": [
{
"userId": "<userId>",
"role":"user|operator",
"name":"<name>",
"photo":"<photo>"
}
]
}]
},
"type":"ntf"
}
Создание/изменение диалога (приходит в вебсокете)
{
"class":".oChatSet.sender",
"model":{
"chatInfo":{
"chatId": "<UpdatedChatId>",
"companyId":"<companyId>",
"created":<created>,
"members": [
{
"userId": "<userId>",
"role":"user|operator|company",
"name":"<name>",
"photo":"<photo>"
}
],
"type": "oper"
}
},
"type":"sys"
}
Закрытие диалога (приходит в вебсокете)
{
"class":".oChatDel.sender",
"model":{
"companyId":"<companyId>",
"chatId":"<chatId>"
},
"type":"sys"
}
Установка статуса активности оператора (онлайн/офлайн) в разрезе компаний
{
"class": ".oStatusSet.sender",
"model":{
"list": [
{"companyId":"<companyId>", "status":"online|offline"}
]},
"chatId":"user+sender"
}
Ответ (асинхронно)
{
"class": ".oStatusSet.sender",
"model":{
"list": [
{"companyId":"<companyId>", "status":"online|offline"}
]},
"type":"sys"
}
| Name | Value | Description |
|---|---|---|
| REST_STATUS_OK | 0 | Успех |
| REST_STATUS_ACCESS_INVALID | 1 | token невалидный, получив challenge необходимо пересчитать |
| REST_STATUS_MISSING_PARAM | 2 | отсутствует обязательный параметр(ы) |
| REST_STATUS_UDID_INVALID | 3 | данный udid не зарегистрирован |
| REST_STATUS_INTERNAL_ERROR | 4 | внутренняя ошибка сервера |
| REST_STATUS_NEW_STREAM_REG | 5 | параллельно былы открыто соединение |
| - | 6 | не используется |
| - | 7 | не используется |
| REST_STATUS_VER_NOT_SUPPORT | 8 | данная версия АПИ не актуальна, нужно обновить приложение |
| REST_STATUS_CHAT_INVALID_DATA | 9 | переданы неверные данные для создания чата |
| REST_STATUS_CHAT_NOT_FOUND | 10 | указанный чат не найден |