API

Service description

Описание сервиса

General information

Общие сведения

Сервис предоставляет доступ к функционалу Sender посредством http(s) транспорта.

Req response format and url

Формат запросов-ответов и 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.

IP connect

В определенные моменты времени сервер присылает клиенту (в 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 - Уникальный идентификатор регистрации устройства в системе. Получается с сервера и сохраняется в настройках приложения;

Device registration

  1. Generation UDID:

    Для генерации нужно использовать железный идентификатор устройства, например IMEI. Идентификатор устройства меняться не должен

      UDID = HMAC-SHA1(Developer-Key, IMEI)
                    

    SHA1 длинной 160 символов

  2. Registration request:

    Вызывает клиент, если у него отсутсвует 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>"
      }
                    
  • developerId(string): ID выданный Сендером для индентификации разработчика;
  • udid(string): Уникальный идентификатор устройства, подписанный разработчиком;
  • pushToken: ID для пуш нотификаций. Обязательно для ios, android.
  • devType(string): тип устройства. Множество знечений ["phone","tablet","desktop"];
  • devModel(string): модель устройства;
  • devManufact(string): производитель устройства (есть в Android), может быть пустым;
  • devOS(string): ОС устройства. Множество знечений ["android","ios","mac","win","linux"];
  • versionOS(string): версия ОС;
  • clientType(string): тип клиентского приложения. Множестов знечений ["android","ios","web","desktop"];
  • clientVersion(string): версия клиентского приложения;
  • language(string): язык приложения ISO 639-1. Множество знечений ["ru","en" ...];
  • companyId(string): (опционально)id компании, которая зарегистрировало устройство;

Параметры "apns..." (только для IOS):

  • apns_Test Устанавливает на сервере путь на gateway.sandbox.push.apple.com и sendertest.pm
  • apns_Local Устанавливает на сервере путь на gateway.push.apple.com и senderlocal.pm
  • apns_AppStore Устанавливает на сервере путь на gateway.push.apple.com и sender.pm

Ответ (синхронно)

  {
    "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)
            

Getting challenge

GET /[request]?udid=&token=

На любой запрос в случае передачи невалидного параметра token, сооединение будет закрыто с ответом:

  {
    "code": "1",
    "challenge": "<challenge>"
  }
            

challenge - рандомное значение из 64 символоd необходимое для рассчета параметра token по алгоритму:

  token = HMAC-SHA256(masterKey, challenge)
            

Параметр token имеет ограниченное время жизни (2 часа). Новое значение challenge вернется при следующем поднятии соединения.

Push token update request

Посылает клиент если на клиенте изменился токен.

POST /token?udid=&token=

  {
    "token":"<Token>",
    "apns":"<Apns>"
  }
            

Параметр apns, (только для IOS), значения:

  • "t" (Test) Устанавливает на сервере путь на gateway.sandbox.push.apple.com и sendertest.pm
  • "l" (Local) Устанавливает на сервере путь на gateway.push.apple.com и senderlocal.pm
  • "a" (AppStore) Устанавливает на сервере путь на gateway.push.apple.com и sender.pm

Ответ (синхронно)

  {
    "code": 0
  }
            

Version set request

POST /version_set?udid=&token=

  {
    "devType": "<DevType>",
    "devModel": "<DevModel>",
    "devManufact": "<devManufact>",
    "devOS":"<devOS>",
    "versionOS":"<versionOS>",
    "clientType":"<clientType>",
    "clientVersion":"<clientVersion>",
  }
            
  • devType(string): тип устройства. Множество знечений ["phone","tablet","desktop"];
  • devModel(string): модель устройства;
  • devManufact(string): производитель устройства (есть в Android), может быть пустым;
  • devOS(string): ОС устройства. Множество знечений ["android","ios","mac","win","linux"];
  • versionOS(string): версия ОС;
  • clientType(string): тип клиентского приложения. Множестов знечений ["android","ios","web","desktop"];
  • clientVersion(string): версия клиентского приложения;

Ответ (синхронно)

  {
    "code": 0
  }
            

Get User Device Additional Info

POST /get_user_dev_info?udid=&token=

  {
    "userId": "<userId>"
  }
            
  • userId(string): идентифкатор пользователя, по которому интересует информация о девайсах, пустая строка "" если интересует информация о себе.

Ответ (синхронно)

  {
    "code": 0,
    "devs": [
      {"sipLogin": "<sipLogin>"}
    ]
  }
            
  • devs(массив): устройства, когда информация запршивается о себе то возвращается только тот девайс - с котрого послан запрос.
  • sipLogin(строка): sip логин.

Get Sip Info

POST /get_sip_info?udid=&token=

  {    
    "sipLogin": "<sipLogin>"
  }
            
  • sipLogin(строка): sip логин.

Ответ (синхронно)

  {
    "code": 0,
    "userId": "<userId>"
  }
            
  • userId(string): идентифкатор пользователя.

Sip Signaling

Отправитель отправляет один раз в начале звонка пакет в 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".

Get Companies Contact Forms

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

POST /get_companies_cf?udid=&token=

  {

  }
              

Ответ (синхронно)

  {
    "code": 0,
    "noDefaultCompanies":[
      "<companyUserId1>", "<companyUserId2>" //...
    ],
    "defaultView": {
      //...
    }
  }
              

noDefaultCompanies - список UserId компаний у которых не дефалтовая форма контакта.

defaultView - фмл дефалтовой карточки, она также может прийти позже асинхроно через обычную форму контакта с CompanyId="!". В ней использется FML {{!meta.!user.<Parameter>}} с помощью которых подставлется данные компании.

После чего асинхронно приходят какрточки компаний у которых не дефалтовая форма контакта. У карточек контактов FormId="contact", RobotId="contact".

Send message

Запрос:

POST /send?udid=&token=

Тело запроса:

  {
    "fs": [
      {
        ...
      }
    ]   
  }
            

в массиве fs передеются обычные асинхронные формы. Если по отправленной форме нужно получить procId и серверное время (time), то в корень json-представления этой формы добавляем уникальный идентификатор cid, который будет получен в ответе

Ответ 200 OK

  {
    "cr": [
      {
        "cid": "<clientMsgId>",
        "packetId": "<serverMsgId - packetId>",
        "time": <time>
      }
    ],
    "code": 0
  }
            

Алгоритм работы с очередью и пакетной отправки

Algorithm

Receive message

Запрос:

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 не вернуть на сервер, он повторит отправку сообщений, которые были в этом пакете

Form state

При получении формы с сервера клиент оповещает о их получении в зависимости от значения поля model.state. Возможные значения и действия по ним:

  • alert : нарастить счетчик новых сообщений, сигналить с максимальной громкостью, вибрировать и (если возможно) мигать вспышкой
  • active (по умолчанию) : нарастить счетчик новых сообщений, просигналить стандартным звуком или вибрацией (в соответствии с текущими настройками системы и приложения)
  • mute : нарастить счетчик новых сообщений
  • invisible : никак не сигнализировать о приходе формы

Text message (send)

Текстовое сообщение представляет собой упрощённую "невидимую" форму вида:

  {
    "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 чата

Text message (receive)

При получении текстовое сообщение представляет собой форму:

  {
    "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 отправителя

Self info

Сохранение, обновление и получение информации о себе

Сохранение, обновление. Если поле не передается, его не изменяем. Чтобы удалить значение - передаем поле с пустым значением.

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
    }
  }
            

Get User Info

Получение информации о пользователе.

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"]. Если не указан, возвращаются все.

Get Operators

Получение списка операторов и ролей компании

POST /get_operators

  {
    "companyId": "<companyId>"
  }
            

Ответ 200 OK

  {
    "operators": [
      {
        "userId":"<userId>",
        "roleId":"<roleId>",
        "name": "<UserName>",
        "photo": "<photoUrl>"          
      }
    ],
    "roles":[
      {
        "roleId":"<roleId>",
        "name": "<RoleName>"
      }
    ],
    "code": 0
  }
            

Get Company Operators (deprecated)

Получение списка операторов компании

POST /get_company_operators

  {
    "companyId": "<companyId>"
  }
            

Ответ 200 OK

  {
    "operators": ["<userId>"],
    "code": 0
  }
            

History

Запрос:

POST /history?udid=&token=

Тело запроса:

  {
    "pos":<pos>,    
    "size":<size>,
    "chatId":"<chatId>"
  }
            

pos - с какой позиции получать сообщения, 0 - с начала, n - c n-го сообщения

size - количество возвращаемых сообщений

Ответ 200 OK

  {
    "msgs": [<msgs>],
    "code": 0
  }
            

SendBar

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 является опциональным свойством любого контакта компании.

Actions

Динамически создаваемые элементы интерфейса приложения (в т.ч. элементы fml-форм) при их актвации пользователем могут инициировать действия, описанные c помощью actions-атрибута:

Значением атрибута actions является массив обьектов, которые описывают действия, выполняемые в порядке следования в массиве.

Каждый обьект одержит обязательное поле: oper - определяющее выполняемую операцию, обязательное поле. Оста

oper extCall (fml only)

Выполнить вызов внешнего сервера с параметрами (опционально), введёнными в фроме. При ответе сервера форма с содержимым ответа отправляется обычным способом Пример:

  {
    "actions":
    [
      {
        "oper":"extCall",
        "url":"<url to external get request>",
        "form_data": true
      }
    ]
  }
            

form_data - признак, следует ли отправлять в запросе поля формы. Поля отправяляются как get-параметры в формате <имя поля>=<значение>&...

oper goTo

Отправить пользователя в указанный интерфейс приложения. Обязательным атрибутом является "to", который принимает значения:

contacts|dialogs|profile|settings

В случае, если action описан в fml-форме, она должна быть отправлена на сервер перед переходом

Пример:

  {
    "actions":
    [
      {
        "oper":"goTo",
        "to":"<to>"
      }
    ]
  }
            

Возможные значения to

  • contacts: список контактов
  • dialogs: список диалогов
  • profile: страницу профиля пользователя
  • settings: страница настроек
  • contact: страница текущего контакта (только в p2p чате)

oper addUser

Добавить пользователя в текущий чат: открыть диалог выбора пользователя и по результату добавить выбранного (выбранных)

Если текущий чат p2p - будет создан новый, групповой чат

Пример:

  {
    "actions":
    [
      {
        "oper":"addUser"
      }
    ]
  }
            

oper viewLink

В поле "link" передается веб ссылка, начиная с http/https, поле обязательно. Открываем стандартный диалог выбора приложений для открытия ссылки, если таковых несколько. Если одно, открываем напрямую, если отсутствует уведомляем об отсутствии.

Пример:

              { "actions" : [ { "oper":"viewLink","link":"<link>" } ] }
            

oper sendMsg

Открыть окно ввода текста и введённый текст отправить сообщением в текущий чат

Пример:

  {
    "actions":
    [
      {
        "oper":"sendMsg"
      }
    ]
  }
            

oper sendMedia

Открыть окно выбора медиа-контента (cпецифическое для типа контента и платформы) и выбранный контент отправить в текущий чат.

Обязательное поле type определяет тип контента. Варианты: sticker, file, photo, video, location

Пример:

  {
    "actions":
    [
      {
        "oper":"sendMedia",
        "type":"<type>"
      }
    ]
  }
            

oper scanCard: scan card by reader (fml only)

При активации элемента с этим oper, показываем диалог сканирования, обращаемся к ридеру, при успешном сканировании строку к номером карты помещаем в поле "card" json-структуры, которую отправляем на серврер как model формы. Остальные ранее введённые данные этой формы также отправляются в этой структуре аналогично обычному submit формы.

Пример:

  {
    "actions":
    [
      {
        "oper":"scanCard"
      }
    ]
  }
            

oper callPhone

В поле "phone" передается телефон в международном формате, без плюса, поле обязательно. Открываем стандартный диалог телефонного вызова с этим номером

Пример:

  {
    "actions":
    [
      {
        "oper":"callPhone", 
        "phone":"380501234567"
      }
    ]
  }
            

oper callRobot

Вызывается робот в текущем чате (чате в котором форма находится).

В поле "class" передается класс робота который вызывается, поле обязательно.

Если авзывается из формы, при нажатии в model посылаются все те же элементы что и при нажатии на обычную кнопку этой формы.

Пример:

  {
    "actions":
    [
      {
        "oper":"callRobot",
        "class":"<robotClass>",
        "data":
        {
          "name":"value"
        }
      }
    ]
  }
            

Данные из обьекта "data" передаются в model вместе с данными формы. Если имена полей совпадают с именами полей в форме данные из "data" считаются более приоритетными

При нажатии клиент-приложение должно послать в этот чат обычный fsubmit запрос:

POST /fsubmit

  {
    "sid": "<sid>",
    "chatId": "<chatId>",
    "model": {},
    "class": "<robotClass>"
  }
            

oper callRobotInP2PChat

В поле "userId" передается UserId пользователя или компании в p2p чат с которым нужно перейти, поле обязательно.

В поле "class" передается класс робота который вызывается, поле обязательно.

При нажатии в model посылаются все те же элементы что и при нажатии на обычную кнопку.

Пример:

  {
    "actions": 
    [
      {
        "oper": "callRobotInP2PChat",
        "userId": "<userId>",
        "class": "<robotClass>"
      }
    ]
  }
            

При нажатии клиент-приложение должно по найти/создать p2p чат и перейти в него, и послать в этот чат обычный fsubmit запрос:

POST /fsubmit

  {
    "sid": "<sid>",
    "chatId": "<chatId>",
    "model": {},
    "class": "<robotClass>"
  }
            

oper startP2PChat

В поле "userId" передается UserId пользователя или компании в p2p чат с которым нужно перейти, поле обязательно.

Пример:

  {
    "actions": 
    [
      {
        "oper": "startP2PChat",
        "userId": "<userId>"
      }
    ]
  }
            

oper selectUser (fml only)

При выборе элемента в поле action которого указан этот oper нужно открыть нативный диалог выбора пользователей из списка контактов.

В диалоге отображаются только зарегистрированные пользователи при "reg":true иначе - все пользователи.

При выборе конкретного пользователя его номер телефона помещается в поле формы, имя которого задано в атрибуте "to".

Если "autosubmit":true форма отправляется на сервер сразу после того, как клиент сделал выбор в списке контактов, иначе - после выбора форма доступна для работы и отправки на сервер обычным способом (кнопкой в форме)

Например:

  {
    "actions": 
    [
      {
        "oper": "selectUser",
        "reg": true,
        "to": "<field name>",
        "autosubmit":true
      }
    ]
  }
            

oper switchView (fml only)

При выборе элемента в поле action которого указан этот oper нужно скрыть элементы, name которых указаны в массиве "hide", и показать элементы, name которых указаны в массиве "show". Т.е. первой группе должен быть назначен "state":"gone" а второй - "state":"visible" выполнена перерисовка формы

  {
    "actions": 
    [
      {
        "oper": "switchView",
        "hide":
        [
          elem1, elem2
        ],
        "show":
        [
          elem3, elem4
        ]
      }
    ]
  }
            

oper coords (fml only)

При выборе элемента в поле action которого указан этот oper нужно открыть окно с картой (google maps), при выборе точки на карте значение поля val должно быть равно занчению широты и долготы с разделителем ";" а поле title должно быть равно адресу выбранной точки.

  {
    "actions":
    [
      {
        "oper": "coords"
      }
    ]
  }
            

oper qrScan

При выборе элемента в поле action которого указан этот oper нужно вызвать окно сканирования qr-кода и отсканированный результат отправить роботу, указанному в поле "class". model отправляемой формы должна содержать результат распознавания кода в поле "qr". Форму результата отправляем в чат указанный в поле "chatId". Например:

  {
    "actions":
    [
      {
        "oper": "qrScan",
        "class":"<robotClass>",
        "chatId":"<chatId>"
      }
    ]
  }
            

В результает отправляем форму:

  {
    "sid": "<sid>",
    "chatId": "<chatId>",
    "model": {
      "qr":"<value>"
    },
    "class": "<robotClass>"
  }
            

Using push

Если для клиента есть сообщения, а он не вычитывает их, сервер может отправить клиенту 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-сообщении

Crash log

В случае, если при получении/обработке ответа/сообщения с сервера произошла ошибка, то клиентское приложение шлёт на сервер форму:

  {
    "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

Alert

Вызов "взбодрить" в чате с параметром 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"
      }
    ]   
  }
            

Client2Client cryptography

Для отправки шифрованного сообщения получателю должны быть соблюдены следующие условия:

  • Чат должен быть p2p
  • У получателя должен быть установлен публичный RSA-ключ для шифрования сообщений
  • У отправителя должна быть сгенерирована пара RSA-ключей

Алгоритм зашифровывания:

  1. Сгенерировать одноразовый ключ длиной 128 бит
  2. Зашифровать содержимое поля text сообщения алгоритмом AES с помощью одноразового ключа
  3. Зашифровать одноразовый ключ алгоритмом RSA с помощью публичного ключа получателя
  4. Соединить зашифрованный ключ и зашифрованное сообщение в один массив, (ключ идёт первым)
  5. Перевести получанный массив в hex и установить результат значением поля text в отправляемом сообщении

Алгоритм расшифровывания:

  1. Взять значение поля text полученного сообщения и перевести его из hex в байтовый массив
  2. Взять первые 64 бита массива и попытаться расшифровать их алгоритмом RSA с использованием своего приватного ключа
  3. Если ключ успешно расшифрован расшифровать с его помощью алгоритмом AES остальную часть сообщения

При возникновении ошибки расшифровки считать сообщение не шифрованным и отображать "как есть"

При возникновении ошибки зашифровывания выводить сообщение пользователю и не отправлять сообщение

File upload

Загрузка файлов/изображений.

  POST /upload?udid=<UDID>&token=<Token>&filename=<FileName>&filetype=<FileType>
            

BODY содержит загружаемый файл в бинарном формате. Максимальный размер файла 104857600 байт.

  {
    "url":"<URL>",
    "code":0
  }
            

FileName, FileType, URL - формат значений не определен.

File image upload

Для загрузки картинок с созданием превью. Клиент-приложение это делает самостоятельно.

Поддерживаемые форматы: jpg, gif, png.

Если картинка большая - то можно запрещать посылать ее как картинику, только как файл (для web - не больше 5 MB).

Превью картинки: Конвертировать в jpg с коэффициентом сжатия 0.6, квадрат 400х400, если оригинальная картинка не квадратная - то из нее берется центральный квадрат. Альфа-канал заполнять белым цветом. Для гиф брать первый кадр (или если это невозможно то картинку-заглушку).

Полная картинка: 1) Для gif - оригинальный gif файл. 2) Для других форматов - конвертировать в jpg с коэффициентом сжатия 0.6, если большая из сторон превышает 1600 - сжимать пропорционально чтобы это сторона стала 1600, если не превышает - то размеры картинки оставлять оригинальными. Альфа-канал заполнять белым цветом.

File user avatar upload

Для загрузки аватаров пользователей.

Будет делать клиент-приложение, скоро будет согласование.

jpg размер 800x800. jpg размер 120x120.

File chat avatar upload

Будет делать клиент-приложение, скоро будет согласование.

jpg размер 120x120.

Enable full version

Активация/деактивация полной версии сендера. После изменения версии необходимо выполнить повторную синхронизацию контактов. Подробнее в разделе Sync Request.

POST /full_version

  {
    "activate":"true|false"
  }
            

Ответ

  {
    "sync_user_ct":"true|false"
  }
            

sync_user_ct - синхронизировать или нет свою контактную книгу

Get Current Chat

Получить текущий чат.

Отправляет клиент в чат с 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
      }
    ]
  }
            

Search

Поиск, обновление 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 при запуске робота.

Delivery

Подтверждение доставки сообщения GET /deliv?udid=&token=&chatId=&packetId=

Ответ 200 OK

  {
    "code": 0
  }
            

Chat add members notification

Оповещение о добавлении пользователя в чат.

Ответ (асинхронно)

{
  "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".

Chat del members notification

Оповещение о удалении участников из чата.

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

Ответ (асинхронно)

  {
    "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".

Chat leave member notification

Оповещение о выходе из чата пользователя.

Получают все пользователи чата, которые участвуют в чате, в том числе и выходящий.

Ответ (асинхронно)

  {
    "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п чата придет второму собеседнику сразу сообщение (меньше отвлекающих сообщений, меньше трафика).

Get bar

Получение бара.

POST /get_bar?udid=&token=

  {
    "barId": "<barId>"
  }
            

Ответ 200 OK

  {
    "bar": {},
    "code": 0
  }
            

Send ui monitoring data

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

POST /send в fs:

  {
    "chatId": "user+sender",
    "model": {
      "type":"<тип устройства, аналогично запросу reg>",
      "model":"<модель устройства, аналогично запросу reg>",
      "ver":"<версия клиентстого приложения, аналогично запросу reg>",
      "udid":<UDID>,
      "events":[
        <массив json структур, представляющих собой события пользовательского интерфейса>
      ]                
    },
    "companyId": "sender",
    "robotId": "uiMonitoring",
    "formId": ""
  }
            

Websocket

Открытие websocket соединения

ws://URL/websocket

Для начала работы сессии необходимо отправить пакет:

  {
    "class": "wsSession",
    "model":{ "udid":"<udid>", "token":"<token>"}
  }
            

Ответ в случае устаревшего токена:

  {
    "class": "wsChallenge",
    "model":{ "challenge":"<challenge>"}
  }
            

Support dialogs list

Список активных диалогов поддержки (приходит в вебсокете)

  {
    "class":".oDlgs.sender",
    "model":{
      "dlgs":[{
        "chatId": "<UpdatedChatId>",
        "companyId":"<companyId>",
        "created":<created>,
        "members": [
          {
            "userId": "<userId>",
            "role":"user|operator",
            "name":"<name>", 
            "photo":"<photo>"
          }
        ]
      }]
    },
    "type":"ntf"
  }
            

Support dialog set

Создание/изменение диалога (приходит в вебсокете)

  {
    "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"
  }
            

Support dialog close

Закрытие диалога (приходит в вебсокете)

  {
    "class":".oChatDel.sender",
    "model":{
      "companyId":"<companyId>",
      "chatId":"<chatId>" 
    },
    "type":"sys"
  }
            

Set operator status

Установка статуса активности оператора (онлайн/офлайн) в разрезе компаний

  {
    "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"
  }
            

Response code

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 указанный чат не найден