
Сразу оговорюсь, что это не готовый модуль с кнопкой, который надо только включить, чтобы заработал. Будет общее описание и куски кода, которые частично или полностью могут использоваться у вас.
[spoiler]
Итак, ситуация следующая: мы общаемся с клиентом в чате, в какой-то момент понимаем, что вопрос требует существенно больше времени и подключения другого специалиста. При этом другой специалист работает в тикетах. Необходимо передать ему всю информацию и при этом не заставлять клиента делать дополнительные телодвижения.
На помощь приходит механизм . Мы сообщаем клиенту о передаче вопроса другому специалисту, затем подключаем служебного бота к чату. Он выводит кнопку, по клику на которую создаётся тикет со всей перепиской из чата. Все последующие сообщения в чате отправляются в созданный тикет. А ответ на тикет отправляет сообщение в чат. Таким образом, для клиента это выглядит как единый диалог в чате с разными специалистами.

У нас открытые линии и тикеты живут на разных установках, интеграция идёт через REST. Если у вас одна установка, реализация будет несколько проще. Её легко собрать из предложенного кода.
По шагам
1. Скачиваем архив . Он содержит класс бота для модуля imbot и языковой файл. Такая аккуратная интеграция в ядро не ломает существующую архитектуру.
В классе бота находим строки:
| const URL = "https://my_ticket_place/rest.php"; // путь к файлу, который публикует информацию в тикеты const SECRET = "UNIQUE STRING"; // секретная строка для публикации сообщений | 
И устанавливаем адрес установки, на которой живут тикеты, и путь к файлу, принимающему запросы из чата (дальше будет информация о нём). Здесь надо обязательно указать свой секрет, чтобы посторонние не могли создать тикет у вас.
2.Теперь надо зарегистрировать бота, для этого в php командной строке выполняем код:
| CModule::IncludeModule("imbot");
var_dump(\Bitrix\ImBot\Bot\TicketGate::register()); | 
В результате вы должны будете увидеть id нового бота.
3.Теперь нужно подготовить файл /my_ticket_place/rest.php, который принимает данные из чата и создаёт тикет. .
Здесь нужно, как минимум, установить секретную строку такую же, как вы установили для бота.
| if ($_REQUEST['hash'] != md5($_REQUEST['timestamp'].'VERY SECRET STRING')) // ваша секретная строка, должна совпадать с тем, что отправляет бот | 
В нашем случае установки работают в разных кодировках: cp1251 и utf8, идёт перекодировка. Уберите "$APPLICATION->ConvertCharset", если не требуется. Остальные параметры: язык, код сайта, категория и пр. делаются в зависимости от ваших потребностей.
4. Далее необходимо отправить ответ из тикета в чат. Для этого добавляем обработчик в /bitrix/php_interface/init.php
| AddEventHandler('support', 'OnBeforeTicketUpdate', "OnBeforeTicketUpdate");
function OnBeforeTicketUpdate($arFields)
{
   if ($arFields['ID'] && $arFields['MESSAGE'] && $arFields['HIDDEN'] != 'Y')
   {
      $uid = $GLOBALS['USER']->GetId();
      if (CTicket::IsSupportTeam($uid) || CTicket::IsAdmin($uid)) // сообщение от сотрудника поддержки
      {
         $arTicket = CTicket::GetList($by = 'id', $order = 'asc', array('ID' => $arFields['ID']), $is_filtered, $CHECK_RIGHTS = "N", $get_extra_names = "N")->Fetch();
         if ($arTicket['SOURCE_SID'] == 'openline')
         {
            $arUser = CUser::GetById($uid)->Fetch();
            $FROM_USER_ID = preg_match('#([0-9]+)@#', $arUser['XML_ID'], $regs) ? $regs[1] : 0;
            $postFields = array(
               'SESSION_ID' => str_replace('imol|', '', $arTicket['CREATED_MODULE_NAME']),
               'MESSAGE' => $GLOBALS['APPLICATION']->ConvertCharset($arFields['MESSAGE'], 'cp1251', 'utf8'),
               'FROM_USER_ID' => $FROM_USER_ID,
            );
            $httpClient = new \Bitrix\Main\Web\HttpClient(array(
                     "socketTimeout" => 20,
                     "streamTimeout" => 60,
                     "disableSslVerification" => true
                  ));
            $httpClient->setHeader('User-Agent', 'Bitrix Ticket Chat Reply');
            $postFields['action'] = 'TicketReply';
            $postFields['timestamp'] = time();
            $postFields['hash'] = md5($postFields['timestamp'].'MY CHAT SECRET STRING');
            $result = $httpClient->post("https://my_openlines_place/openlines_rest.php", $postFields);
            try
            {
               $result = str_replace("\xEF\xBB\xBF", '', $result);
               $ar = \Bitrix\Main\Web\Json::decode($result);
               if ($ar['status'] != 'success')
                  return false;
            }
            catch (\Bitrix\Main\ArgumentException $e)
            {
               AddMessage2Log($result);
               echo $result;
               return false;
            }
         }
      }
   }
   return $arFields;
} | 
Здесь ставим соответственно свою секретную строку и путь к скрипту, который принимает ответы из тикета в чат.
| 
            $postFields['hash'] = md5($postFields['timestamp'].'MY CHAT SECRET STRING');
            $result = $httpClient->post("https://my_openlines_place/openlines_rest.php", $postFields);
 | 
5. Теперь нужно на той установке, где живут открытые линии, создать скрипт openlines_rest.php, о котором говорилось в п.4.
Он довольно простой, поэтому опубликую код прям здесь:
| <?
define("NO_AGENT_STATISTIC","Y");
define("NO_AGENT_CHECK", true);
define("DisableEventsCheck", true);
define("NOT_CHECK_PERMISSIONS", true);
require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_before.php");
if (!CModule::IncludeModule("im"))
   die('{"status":"error","message":"system error '.__LINE__.'"}');
if (!CModule::IncludeModule("imopenlines"))
   die('{"status":"error","message":"system error '.__LINE__.'"}');
if (abs(time() - $_REQUEST['timestamp']) > 300)
   die('{"status":"error","message":"system error '.__LINE__.'"}');
if ($_REQUEST['hash'] != md5($_REQUEST['timestamp'].'DONT SAY THIS TO ANYONE!'))
   die('{"status":"error","message":"system error '.__LINE__.'"}');
if (!$arSession = \Bitrix\ImOpenlines\Model\SessionTable::getList(Array(
   'select' => Array('ID', 'CHAT_ID', 'START_ID', 'END_ID', 'CONFIG_ID'),
   'filter' => Array('ID' => $_REQUEST['SESSION_ID'])
))->fetch())
   die('{"status":"error","message":"system error '.__LINE__.'"}');
$arFields = array(
   "MESSAGE_TYPE" => IM_MESSAGE_CHAT,
   "TO_CHAT_ID" => $arSession['CHAT_ID'],
   "FROM_USER_ID" => $_REQUEST['FROM_USER_ID'],
   "MESSAGE" => $_REQUEST['MESSAGE'],
   "URL_PREVIEW" => "Y",
   "SKIP_USER_CHECK" => "Y",
);
define('TICKET_TRACKBACK', 'defined');
if ($id = CIMMessenger::Add($arFields))
   echo '{"status":"success","message":"id '.$id.'"}';
else
   die('{"status":"error","message":"system error '.__LINE__.'"}');
?> | 
Опять же не забываем установить свой секрет:
| if ($_REQUEST['hash'] != md5($_REQUEST['timestamp'].'DONT SAY THIS TO ANYONE!')) | 
6. И последний шаг: связать пользователей двух разных установок. В предложенном мной методе используется нехитрая связь через внешний код. На установке, где живут тикеты, у пользователя должен быть указан внешний код вида
| <ID с установки открытых линий>@openlines | 

Заключение
Надеюсь, мои наброски помогут кому-то внедрить открытые линии в своей компании. Фактически, подобное решение может использоваться для интеграции открытых линий с любой системой, будь то задачи, живая лента, электронная почта, даже 1С.
 
															 
			 
      
Можно взять этот способ за основу, но писать нужно будет свой.