You probably heard that Microsoft recently released a new framework for building multi-channel integrations with third-party vendors called Channel Integration Framework. By using this framework, you can embed an external web page or service directly into Dynamics CE and implement voice calls as an example. In this article, I would like to give you an overview of how to build Twilio Voice calls app and embed it using CIF into CRM. I will mostly focus on implementing Twilio infrastructure as CIF itself very well documented.
In simple words, Channel Integration Framework is an additional tab on the right side of the Dynamics CE, which shows you some external web page. You can expand and collapse it when needed (also programmatically). Previously we had to implement this functionality using some hacks and change the DOM model of the application. Now it is a fully supported approach which is really nice to have. Let’s see how it looks like.
There is also some javascript SDKs which you can use to interact with this pane. More information about the architecture and SDKs you can read here: Channel Integration Framework. You can read how to set up this framework here: Get Channel Integration Framework. Microsoft also provides a demo application which was built using .Net Core and requires Azure subscription. From my point of view, it is too much for a simple application and creates additional complexity. In addition, the tutorial doesn’t provide information about configuring Twilio, which is used for calls.
Let’s check how to build a simple demo using only js and host it inside Dynamics CE.
First of all, you will need to set up a Twilio account. I encourage you to upgrade it to a paid version as it will give much more flexibility. You need to buy a phone number which supports voice calls. More information here: How to Search for and Buy a Twilio Phone Number from Console. Once you have a phone number, you can start with the implementation. First of all, we need to create a TwiML app. A TwiML Application is a set of URLs and other configuration data that tells Twilio how to handle incoming calls or messages. Let’s create one. Please go to TwiML Apps, and create a new app. Provide a name for the app, all other fields might be blank so far. I will call the app “TestApp.” Save somewhere SID as you will need it for compatibility token. Next step is to create Twilio Function which will generate compatibility token for us. Please read more about Twilio compatibility token here: Twilio capability tokens. Twilio Function is a serverless environment which empowers developers to quickly and easily create production-grade, event-driven Twilio applications. Like Azure Functions from Microsoft. Using Twilio function, we can quickly generate compatibility token. Please navigate to the following URL and create a new function: Twilio Functions. Choose Blank from the templates. Once the function is created, you can provide a name. Let’s call it: token. The path could be /get_token. Set “Check for valid Twilio signature” to false so our function will be available for everyone on the web. Don’t forget to Save changes. Switch to the “Configure” tab and check environment variables. Create three variables CALLER_ID, TWIML_APP_SID, and IDENTITY. Variable CALLER_ID is equal to your Twilio number, which supports phone calls. The second variable TWIML_APP_SID is equal to your TwiML App SID. The third variable, called IDENTITY, will identify our client. It can be “testcaller” as an example. Usually, every client should use a different identity, so the system will know which client is online or offline and redirect incoming calls. We don’t need this functionality as we will have only one client which will handle all requests. Please also be sure that option Enable ACCOUNT_SID and AUTH_TOKEN is activated. Save changes. Configuration tab should look like on the picture below:
Now we are ready to write some code for our function. Here is the example of Twilio function which generates compatibility token. Switch to your newly created function and past this code.
exports.handler = function(context, event, callback) { let response = new Twilio.Response(); // Add CORS Headers let headers = { "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Methods": "GET", "Content-Type": "application/json" }; // Set headers in response response.setHeaders(headers); response.setStatusCode(200); let ClientCapability = require('twilio').jwt.ClientCapability; const identity = context.IDENTITY; const capability = new ClientCapability({ accountSid: context.ACCOUNT_SID, authToken: context.AUTH_TOKEN, }); capability.addScope(new ClientCapability.IncomingClientScope(identity)); capability.addScope(new ClientCapability.OutgoingClientScope({ applicationSid: context.TWIML_APP_SID, clientName: identity, })); // Include identity and token in a JSON response response.setBody({ 'identity': identity, 'token': capability.toJwt() }); callback(null, response); };
Once code is updated, use “Path” field to get the URL of your function. The URL will have the following format: https://wine-viper-1111.twil.io/get_token. Open it in the separate browser tab to check that it works. You should see something like the this:
{"identity":"testcaller", "token":"cRRS135O6LJ4wwKvDRA_1k8DPC61Jo21TjFE" }
Now we need to create another function for incoming calls. This function will redirect all incoming calls to our client. Create a new function and call it “incomingcall“. Here is the code of the function:
exports.handler = function(context, event, callback) { let twiml = new Twilio.twiml.VoiceResponse() twiml.dial().client(context.IDENTITY); callback(null, twiml) };
Here is the screenshot of how the function looks like:
Don’t forget to turn off “Check for valid Twilio signature“. Now go back to your TwiML app. You can use the following link: TwiML apps. Configure your app to use incoming call function URL.
Don’t forget to save changes in your TestApp. The last part is to configure your phone number to use your app. Go to phone numbers. Please use the following link: Phone numbers. And click “Manage numbers”. Open your number and configure it to use our App.
Now we’ve done with configuring Twilio infrastructure and can switch to our CIF app.
Here is HTML which can process incoming calls:
<script src="https://media.twiliocdn.com/sdk/js/client/v1.7/twilio.js"></script> <script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script> <script type="text/javascript"> var incomingConnection = null; jQuery(document).ready(function () { jQuery.getJSON('https://wine-viper-your_number.twil.io/get_token') .done(function (data) { jQuery("#twistatus").text("Token recieved"); Twilio.Device.setup(data.token, { debug: true }); Twilio.Device.ready(function (device) { jQuery("#twistatus").text("Client Ready"); }); Twilio.Device.error(function (error) { jQuery("#twistatus").text('Client Device Error: ' + error.message); }); Twilio.Device.connect(function (conn) { jQuery("#twistatus").text('Call established'); }); Twilio.Device.disconnect(function (conn) { conn.disconnect(function () { jQuery("#twistatus").text("Call has ended"); }); }); }); Twilio.Device.incoming(function (conn) { incomingConnection = conn; jQuery("#twistatus").text("Incomming from: " + conn.parameters.From); }); }); </script></pre> <div id="twistatus"> </div> <pre><br /> <button id="answer">Answer</button>
With this page, you can receive incoming calls. Don’t forget to change link https://wine-viper-your_number.twil.io/get_token. You can also update this page to perform outgoing calls if needed. The last part is to integrate our page into CIF. You need to host this page as a web resource in Dynamics CE and then configure CIF. Please use the following link for more information: Configure channel provider. The most important parameter is the Channel URL, which should contain the URL of our web resource. To access available CIF API please read following: Pass a Dynamics 365 URL to a widget library. Please also notice that Channel Integration Framework only supports Unified Interface.
I hope you got the idea of how to use Twilio as a channel provider and integrate it into CIF.