For the complete documentation index, see llms.txt. This page is also available as Markdown.

Callback: перезваниваем клиенту и заводим в IVR

Введение

Сценарий «callback» (обратный звонок) полезен, когда входящая связь для абонента дорогая (международные или межгород звонки, роуминг) либо когда нужно, чтобы за соединение платила компания, а не клиент. Как только клиент дозванивается, MikoPBX сбрасывает входящий вызов и сама перезванивает абоненту, а после ответа заводит его в IVR (голосовое меню) — дальше звонок идёт обычным внутренним маршрутом.

Это не то же самое, что модуль «Автообработка пропущенных»: тот фиксирует пропущенный звонок и заставляет сотрудника перезвонить клиенту. Здесь же перезвон выполняется сразу и автоматически, без участия оператора, с заводом абонента в IVR.

Реализуется связкой из двух частей: кастомный контекст dialplan в extensions.conf (обёртка с паузой перед набором) и приложение dialplan на PHP-AGI, которое ставит обратный звонок.

1. Добавьте кастомный контекст в extensions.conf

Перейдите в раздел «Кастомизация системных файлов», откройте на редактирование файл extensions.conf и добавьте в конец контекст-обёртку:

[callback-originate]
exten => _[+0-9].,1,Wait(4)
 same => n,Goto(outgoing,${EXTEN},1)

Контекст выжидает 4 секунды (чтобы входящая нога успела корректно завершиться), а затем отправляет вызов в контекст outgoing — то есть набирает номер абонента по вашим исходящим маршрутам.

2. Создайте приложение dialplan

Добавьте новое приложение dialplan (см. Приложения диалпланов), тип кода — «PHP-AGI скрипт», и вставьте код:

<?php
require_once 'Globals.php';

use MikoPBX\Core\Asterisk\AGI;
use MikoPBX\Core\System\Util;
use MikoPBX\Core\System\SystemMessages;

const CALLBACK_WHITELIST    = [];                   // пусто = для всех
const CALLBACK_IVR_EXTEN    = '2003';               // номер IVR в MikoPBX
const CALLBACK_IVR_CONTEXT  = 'internal';
const CALLBACK_ORIG_CONTEXT = 'callback-originate'; // контекст-обёртка с Wait
const CALLBACK_TIMEOUT      = 60000;                // мс: Wait(4) + дозвон

$agi    = new AGI();
$raw    = (string)$agi->get_variable('CALLERID(num)', true);
$caller = preg_replace('/\D/', '', $raw);

if ($caller === '') {
    SystemMessages::sysLogMsg('Callback', "Empty CID ($raw)", LOG_WARNING);
    return;
}
if (CALLBACK_WHITELIST !== [] && !in_array($caller, CALLBACK_WHITELIST, true)) {
    return; // не наш CID — звонок пойдёт обычным маршрутом
}

// 1. Ставим обратный звонок (AMI-экшен живёт в ядре, независимо от AGI).
try {
    $am = Util::getAstManager('off');
    $am->Originate(
        'Local/' . $caller . '@' . CALLBACK_ORIG_CONTEXT . '/n',
        CALLBACK_IVR_EXTEN,
        CALLBACK_IVR_CONTEXT,
        1,
        null, null,
        CALLBACK_TIMEOUT,
        $caller,
        '__ISCALLBACK=1',
        null,
        true
    );
    SystemMessages::sysLogMsg('Callback', "Scheduled callback $caller -> IVR " . CALLBACK_IVR_EXTEN, LOG_NOTICE);
} catch (\Throwable $e) {
    SystemMessages::sysLogMsg('Callback', 'Originate failed: ' . $e->getMessage(), LOG_ERR);
    return; // не роняем входящий, если originate не ушёл
}

// 2. Завершаем входящий штатным путём MikoPBX (сам выставит M_DIALSTATUS и Hangup).
$agi->exec_goto('internal', 'hangup', '1');

3. Настройте константы

Константа
Назначение

CALLBACK_WHITELIST

Белый список входящих CID, кому доступен callback. Пустой массив — перезваниваем всем дозвонившимся

CALLBACK_IVR_EXTEN

Номер IVR (или другого назначения), куда попадёт абонент после ответа на обратный звонок

CALLBACK_IVR_CONTEXT

Контекст назначения. Для внутренних номеров и IVR — internal

CALLBACK_ORIG_CONTEXT

Имя кастомного контекста-обёртки из шага 1

CALLBACK_TIMEOUT

Таймаут (мс) на дозвон до абонента, с запасом на Wait(4)

4. Направьте входящий вызов на приложение

В разделе «Входящие маршруты» укажите в качестве назначения (для нужного провайдера или DID) созданное приложение dialplan. После этого каждый такой входящий будет сбрасываться и перезваниваться автоматически.

Важные моменты

  1. Обратный звонок уходит по вашим исходящим маршрутам — за него платит компания. Ограничьте доступ через CALLBACK_WHITELIST, иначе callback можно использовать для бесплатных звонков за ваш счёт.

  2. Номер абонента берётся из CALLERID(num) и чистится от нецифровых символов. Он должен быть в формате, который принимают ваши исходящие маршруты и шаблоны номеров; при необходимости нормализуйте номер в контексте [callback-originate].

  3. IVR с номером CALLBACK_IVR_EXTEN (в примере 2003) должен существовать в MikoPBX (см. Базовый пример IVR).

  4. Защита от зацикливания: обратный вызов помечается переменной __ISCALLBACK=1 — используйте её в кастомном dialplan, если нужно исключить повторный заход в скрипт при обратном звонке.

  5. Все события пишутся через SystemMessages::sysLogMsg('Callback', ...) — ищите по тегу Callback в системном журнале.

  6. Скрипт не является завершённым продуктом, но открыт для кастомизации.

Last updated

Was this helpful?