- Joined
- Jan 7, 2026
- Messages
- 3
- Reaction score
- 0
Hello,
I am looking for a solution for a client.
I would like to know if, with the call scripts, it would be possible to intercept all incoming calls in order to send the following information to a REST API:
- Caller
- Call ID
- Recipient
- Start time of the call
- Answer time of the call
- End time of the call
The goal would then be to allow 3CX’s standard routing and operation to function as usual.
Currently, I have tested the following code which works for a single recipient.
C#:/* * Time Base Call Routing with REST Webhook * Calls will be intercepted and redirected to the specified DestinationDN during the following times: * Monday to Sunday: 5:30 PM to 7:00 AM * Webhook notifications ("Incoming" and "Terminated") are sent to your REST API. */ #nullable disable using CallFlow; using System; using System.Threading.Tasks; using TCX.Configuration; using TCX.PBXAPI; using System.Collections.Generic; using System.Linq; using CallFlow.CFD; namespace interceptcall { public class InterceptInboundCall : ScriptBase<InterceptInboundCall> { // The destination DN to which the call will be redirected const string DestinationDN = "1000"; // URL du webhook REST const string WebhookUrl = "http://my-ip:8080/api/webhook/3cx"; // Définition du planning d'interception static readonly Schedule schedule = new Schedule(RuleHoursType.SpecificHours) { { DayOfWeek.Monday, new Schedule.PeriodOfDay(TimeSpan.FromHours(17.5), TimeSpan.FromHours(24)) }, { DayOfWeek.Monday, new Schedule.PeriodOfDay(TimeSpan.FromHours(0), TimeSpan.FromHours(7)) }, { DayOfWeek.Tuesday, new Schedule.PeriodOfDay(TimeSpan.FromHours(17.5), TimeSpan.FromHours(24)) }, { DayOfWeek.Tuesday, new Schedule.PeriodOfDay(TimeSpan.FromHours(0), TimeSpan.FromHours(7)) }, { DayOfWeek.Wednesday, new Schedule.PeriodOfDay(TimeSpan.FromHours(17.5), TimeSpan.FromHours(24)) }, { DayOfWeek.Wednesday, new Schedule.PeriodOfDay(TimeSpan.FromHours(0), TimeSpan.FromHours(7)) }, { DayOfWeek.Thursday, new Schedule.PeriodOfDay(TimeSpan.FromHours(17.5), TimeSpan.FromHours(24)) }, { DayOfWeek.Thursday, new Schedule.PeriodOfDay(TimeSpan.FromHours(0), TimeSpan.FromHours(7)) }, { DayOfWeek.Friday, new Schedule.PeriodOfDay(TimeSpan.FromHours(17.5), TimeSpan.FromHours(24)) }, { DayOfWeek.Friday, new Schedule.PeriodOfDay(TimeSpan.FromHours(0), TimeSpan.FromHours(7)) }, { DayOfWeek.Saturday, new Schedule.PeriodOfDay(TimeSpan.FromHours(17.5), TimeSpan.FromHours(24)) }, { DayOfWeek.Saturday, new Schedule.PeriodOfDay(TimeSpan.FromHours(0), TimeSpan.FromHours(7)) }, { DayOfWeek.Sunday, new Schedule.PeriodOfDay(TimeSpan.FromHours(17.5), TimeSpan.FromHours(24)) }, { DayOfWeek.Sunday, new Schedule.PeriodOfDay(TimeSpan.FromHours(0), TimeSpan.FromHours(7)) } }; // Méthode pour envoyer un webhook à ton API REST private async Task SendWebhookAsync(string status) { try { string callerID = MyCall.Caller?.CallerID ?? "Unknown"; string calledID = MyCall.DN?.ToString() ?? "Unknown"; string json = "{" + $"\"CallID\":\"{MyCall.CallID}\"," + $"\"From\":\"{callerID}\"," + $"\"To\":\"{calledID}\"," + $"\"Status\":\"{status}\"," + $"\"Timestamp\":\"{DateTime.UtcNow:O}\"" + "}"; using var client = new System.Net.Http.HttpClient(); var content = new System.Net.Http.StringContent(json, System.Text.Encoding.UTF8, "application/json"); var response = await client.PostAsync(WebhookUrl, content); MyCall.Trace($"Webhook '{status}' sent. Status: {response.StatusCode}"); } catch (Exception ex) { MyCall.Error($"Error sending webhook '{status}': {ex.Message}"); } } public override async void Start() { try { await Task.Run(async () => { try { MyCall.Debug($"Script start delay: {DateTime.UtcNow - MyCall.LastChangeStatus}"); MyCall.Debug($"Incoming connection {MyCall} from {MyCall.Caller}"); bool intercepted = false; var ps = MyCall.PS as PhoneSystem; // Webhook "Incoming" at the beginning Task.Run(() => SendWebhookAsync("Incoming")); // Webhook "Terminated" at the end of the call MyCall.OnTerminated += () => { Task.Run(() => SendWebhookAsync("Terminated")); }; if (MyCall.Caller.DN is ExternalLine externalLine) { var DIDNumber = MyCall.Caller["inbound_did"]; var CallerID = MyCall.Caller.CallerID; var currentTime = externalLine.Now(out var utc, out var timezone, out var groupmode); // Intercept calls during the specified schedule if (schedule.IsActiveTime(currentTime)) { string[] DIDs = { "*" }; // Allow all DIDs string[] Callers = { "*" }; // Allow all Callers var destination_struct = new DestinationStruct(ps.GetDNByNumber(DestinationDN)); if ((DIDs.Contains(DIDNumber) || DIDs.Contains("*")) && (Callers.Contains(CallerID) || Callers.Contains("*"))) { try { var result = await MyCall.RouteToAsync(destination_struct); MyCall.Info($"{CallerID} -> {DIDNumber} has been redirected to {DestinationDN} ({result})"); intercepted = true; } catch (Exception ex) { MyCall.Info($"{CallerID} -> {DIDNumber}: interception failed. '{DestinationDN}' is not reachable: {ex}"); } } else { MyCall.Info($"{CallerID} -> {DIDNumber}@{currentTime}: Default CallerID/DID based routing will be applied"); } } } MyCall.Return(intercepted); } catch (Exception ex) { MyCall.Error($"Script execution failed: {ex}"); MyCall.Return(false); } }); } catch (Exception ex) { MyCall.Error($"Task execution failed: {ex}"); MyCall.Return(false); } } } }
The API result is as follows:
Result:
info: 3cxJira.Controllers.3cxController[0]
CallID: 1850 | From: 0+0000000000 | To: Wroutepoint.20: ROUTER | Status: Incoming | Timestamp: 01/05/2026 17:32:01 +00:00
CallID: 1850 | From: 0+000000000 | To: Wroutepoint.20: ROUTER | Status: Terminated | Timestamp: 01/05/2026 17:32:22 +00:00
The problem is that there is only one recipient, and I don't know when they pick up the call.
Thank you in advance.
Last edited: