Creare una campagna di richieste in uscita per facilitare le chiamate automatiche.
Utilizzate il 3CX Call Control API per automatizzare le campagne di chiamate in uscita. Collegate un elenco di numeri di telefono ad un IVR, riproducete un messaggio automatico e trasferite le chiamate a diverse destinazioni in base alle selezioni del menu IVR. A differenza della tradizionale composizione in uscita, questo metodo offre flessibilità nella messaggistica, nell’instradamento delle chiamate e nell’integrazione con CRM o database. Continuate a leggere per saperne di più.
Quando usare lo script della campagna Prompt in uscita

La cancellazione di un volo è un esempio perfetto. Una compagnia aerea può avvisare i passeggeri con un messaggio registrato e fornire opzioni di menu per collegarli all’assistenza.
Questo è un caso d’uso di base, ma può essere ampliato. È possibile costruire un IVR personalizzato con gestione degli input DTMF e controllo del flusso audio per le campagne in uscita.
Per ulteriori esempi, consultare il repository ufficiale 3CX su GitHub.
Impostazione della gestione delle chiamate e integrazione API
Creare un IVR 3CX, aggiungerlo al Call Control API Access e selezionarlo dall’elenco delle estensioni..
Avvio della chiamata
L’interfaccia utente del client utilizza una semplice area di testo per inserire un elenco di numeri separati da virgole.
const destinations = source
.split(',')
.map((num) => num.trim())
.filter(Boolean);
Una struttura a coda elabora le chiamate una per una. Le chiamate senza risposta o occupate possono essere messe in coda per essere richiamate.
destinations.forEach((destNumber) => this.callQueue.enqueue(destNumber));
Logica di chiamata
La funzione seguente recupera il primo numero dalla coda e inizia l’elaborazione.
public async makeCallsToDst() {
if (this.callQueue.isEmpty()) return;
const destNumber = this.callQueue.dequeue();
// …
Prima di comporre, il sistema controllare la connessione al PBX e assicurarsi che l’interno di origine non sia in uso.
if (!this.sourceDn || !this.externalApiSvc.connected) {
if (destNumber)
this.failedCalls.push({
callerId: destNumber,
reason: NO_SOURCE_OR_DISCONNECTED,
});
return;
}
const participants = this.getParticipantsOfDn(this.sourceDn);
if (participants && participants.size > 0) {
if (destNumber)
this.failedCalls.push({
callerId: destNumber,
reason: CAMPAIGN_SOURCE_BUSY,
});
return;
}
//…
Effettuare una chiamata
La chiamata viene effettuata utilizzando il primo dispositivo disponibile.
L’elenco dei dispositivi disponibili per un determinato DN si trova nello stato del controllo chiamate.
try {
const source = this.fullInfo?.callcontrol.get(this.sourceDn);
const device: DNDevice | undefined = source?.devices?.values().next().value;
if (!device?.device_id) {
throw new BadRequest('Devices not found');
}
const response = await this.externalApiSvc.makeCallFromDevice(
this.sourceDn,
encodeURIComponent(device.device_id),
destNumber,
);
//…
Il metodo makeCallFromDevice utilizza questo endpoint:
public makeCallFromDevice(source: string, deviceId: string, dest: string) {
const url = '/callcontrol' + `/${source}` + '/devices' + `/${deviceId}` + '/makecall';
return this.fetch!.post(
url,
{
destination: dest,
},
{
headers: {
'Content-Type': 'application/json; charset=utf-8',
},
},
);
}
Gestione degli errori
Se il PBX accetta la richiesta, l’ID della chiamata viene memorizzato. In caso contrario, viene registrato un errore.
if (response.data.result?.id) {
this.incomingCallsParticipants.set(response.data.result.id, response.data.result);
} else {
this.failedCalls.push({
callerId: destNumber!,
reason: response?.data?.reasontext || UNKNOWN_CALL_ERROR,
});
}
//…
Gli errori tra l’applicazione e il PBX vengono gestiti qui:
//...
} catch (error: unknown) {
if (axios.isAxiosError(error)) {
this.failedCalls.push({
callerId: destNumber!,
reason: error.response?.data.reasontext || UNKNOWN_CALL_ERROR,
});
} else {
this.failedCalls.push({
callerId: destNumber!,
reason: UNKNOWN_CALL_ERROR,
});
}
}
Gestione degli eventi dei partecipanti
Una connessione WebSocket tiene traccia dello stato dell’IVR, avvia nuove chiamate e gestisce i partecipanti.
Per maggiori dettagli sulla struttura degli eventi WebSocket e su altri aspetti correlati, consultare questa guida.
private wsEventHandler = (json: string) => {
try {
const wsEvent: WSEvent = JSON.parse(json);
if (!this.externalApiSvc.connected || !wsEvent?.event?.entity) {
return;
}
const { dn, type } = determineOperation(wsEvent.event.entity);
//...
Quando si verifica un aggiornamento, l’applicazione recupera e memorizza i nuovi dati.
case EventType.Upset:
{
this.externalApiSvc
.requestUpdatedEntityFromWebhookEvent(wsEvent)
.then((res) => {
const data = res.data;
set(this.fullInfo, wsEvent.event.entity, data); // update local state
if (dn === this.sourceDn) {
if (type === PARTICIPANT_TYPE_UPDATE) {
/**
* handle here update of participants
*/
}
}
})
.catch((err) => {
if (axios.isAxiosError(err)) {
console.error(`AXIOS ERROR code: ${err.response?.status}`);
} else console.error('Unknown error', err);
});
}
break;
Possiamo usare questo URL per richiedere l’entità aggiornata ed eseguire un aggiornamento di stato incrementale per la nostra applicazione (controllare DN Update Request):
public requestUpdatedEntityFromWebhookEvent(ws: WSEvent) {
return this.fetch.get(ws.event.entity);
}
Quando un partecipante viene rimosso, la campagna continua.
case EventType.Remove: {
const removed = set(this.fullInfo, wsEvent.event.entity, undefined);
if (dn === this.sourceDn) { // update related to our campaign handler
if (type === PARTICIPANT_TYPE_UPDATE) {// update related to call participant
/**
* handle here removed participants
*/
if (removed?.id) {
//...
if (!participants || participants?.size < 1) { // Handler is free
this.makeCallsToDst(); // continue with campaign
}
}
}
}
}
Possiamo utilizzare questo gestore di eventi all’interno dell’ascoltatore di eventi WebSocket.
ws.on('message', (buffer) => {
const message = decoder.decode(buffer as Buffer);
wsEventHandler(message);
});
Altri script di flusso di chiamata disponibili
Sul nostro sito web. abbiamo una raccolta di script per il flusso di chiamate. Consultateli e scoprite come potete automatizzare 3CX per soddisfare le vostre esigenze.



