Integrate third-party dialers with Dynamics 365 conversation intelligence (preview)
[This article is prerelease documentation and is subject to change.]
With this integration, Dynamics 365 users can use dialers provided by third-party telephony companies such as Twilio Flex, to make and receive phone calls in Dynamics 365, and get real-time AI-generated insights and rich post-call analysis of their calls. Learn more about Dynamics 365 conversation intelligence
Important
- This is a preview feature.
- Preview features aren’t meant for production use and might have restricted functionality. These features are subject to supplemental terms of use, and are available before an official release so that customers can get early access and provide feedback.
How the integration works
At a high-level, the integration consists of three parts:
Register the provider: Register the provider details and get the users list to be recorded by using the conversation intelligence API.
Fork the media: Fork the audio stream to the conversation intelligence recorders using a SIPREC protocol.
Send real-time events: To enable real-time transcription and call insights experience, send UI events from the provider's client UI to Dynamics 365 conversation intelligence.
For an example integration between Dynamics 365 conversation intelligence and a third-party telephony provider, Twilio Flex, see Integrate Twilio Flex with Dynamics 365 conversation intelligence.
The following diagram illustrates how the integration works:
Step 1: Register the provider
Add API permission for media recording:
In the Microsoft Entra ID application that you created, go to API permissions.
Select Add a permission.
Under APIs my organization uses search for Media Recording for Dynamics 365 Sales and select it:
Add Users.Read.All permission and select Add permission
Note
Make sure to get the admin consent for the permission to be able to call the conversation intelligence API in app context. Learn more about permissions and consent.
Get the token to run the Conversation Intelligence APIs using the app created in the previous section:
curl -X POST -H 'Content-Type: application/x-www-form-urlencoded' https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/token -d 'client_id=<your app id>' -d 'grant_type=client_credentials' -d 'scope=00001111-aaaa-2222-bbbb-3333cccc4444/.default' -d 'client_secret=<your app secret>'
The
scope
parameter specifies the application ID of the Conversation intelligence app. Don't change this value.For more information about the curl command, see Get Microsoft Entra ID tokens for service principals.
Call the following conversation intelligence API to register the third-party service provider:
POST /api/v1.0/providers/tenants
Specify the following parameters in the request body:
orgID: Specify the Dynamics 365 org ID.
Type: Specify "custom" for third-party dialers.
hosting: Specify the hosting type of the telephony provider. For example, "cloud" or "on-premises".
AccountId: Specify the account ID of the telephony provider.
CerfificateSubjectName and CertificateIssuer: Specify the certificate details of the telephony provider.
SourceIPNetwork: Specify the IP address of the SIPREC client. Specify "0.0.0.0" if you don't want to restrict the IP address.
The following snippet is an example of the request body:{ "orgId": "ad3dca46-962a-4895-9f85-d25f3828781f", "Type": "custom", "hosting": "cloud", "displayName": "Test Custom Provider", "AuthenticationDetails": { "AccountId":"adxxxxx-xxxx-xxxx-xxxx-xxxxxxxx", "CertificateSubjectName": "certSubject", "CertificateIssuer": "issuer", "SourceIPNetwork": "0.0.0.0" } }
For more information about the API, see the Swagger documentation.
Call the following conversation intelligence API to get the list of users to record:
GET /api/v1.0/providers/users
After the Dynamics 365 Sales admin creates the recording policy, the provider can use this endpoint to filter the media that will be forked to conversation intelligence recorders.
Step 2: Fork the media (SIPREC integration)
Conversation Intelligence recorders implement the standard SIPREC protocol.
The communication is secured using SIPS (port 5061) and SRTP protocols. The authentication is done using mTLS in the SIPS message connection, and is based on the certificate provided to the API – which means that the provider must be registered for a tenant to establish SIPS connection.
The following screenshot illustrates the communication between the SIPREC client and SIPREC server:
The following metadata are required for conversation intelligence:
Headers:
Header Name | Description | Value Example |
---|---|---|
Call-ID | Unique identifier of the call. This ID is used to correlate SIP signals and user actions such as start/stop recording. | efxxxxxxxxxxxxx |
X-AccountId | Unique identifier of the account the call belongs to. This ID is used for authentication and authorization. This is the same account ID registered in the API for the tenant. | ACxxxxxxxxxxxxxxxxxxxxxxx |
Metadata
Metadata key name | Description | Value Example |
---|---|---|
Role | Indicates whether it's an inbound or outbound call for the seller. | ["inbound", "outbound"] |
CallerDisplayName | Caller display name. If not available, phone number is displayed. | Kenny Smith |
CalleeDisplayName | Recipient's display name. If not available, phone number is displayed. | Alex Baker |
Here are examples of invite and bye messages with the required headers and metadata:
INVITE message:
INVITE sip:SRS@media.recording.dynamics.com:5061;transport=tls SIP/2.0
Via: SIP/2.0/TLS 84.172.x.x:5061;branch=z9hG4bK4fa2.cdabfe83d76d3c41987802096d3b342a.0;received=172.16.x.x;rport=40334
Via: SIP/2.0/UDP 172.25.x.x:5060;rport=5060;branch=z9hG4bK917ce574-0345-4c3d-9b63-d98c2c57dbe6_c3356d0b_599-10236398515455707148
To: <sip:SRS@media.recording.dynamics.com:5061;transport=tls>
From: <sip:SRC@sip.provider.com>;tag=66790678_c3356d0b_917ce574-0345-4c3d-9b63-d98c2c57dbe6
Call-ID: efab0870bc597cb3fb56010921e2f57f
CSeq: 1 INVITE
Contact: <sip:SRC@172.25.x.x:5060;transport=udp>;+sip.src
Max-Forwards: 67
Record-Route: <sip:84.172.x.x:5061;transport=tls;r2=on;lr>,<sip:84.172.x.x;r2=on;lr>
User-Agent: provider Gateway
Allow: INVITE,ACK,CANCEL,OPTIONS,BYE,REFER,NOTIFY
Require: siprec
Content-Length: 3194
Content-Type: multipart/mixed;boundary=\"----=_Part_1253_283419664.1674116473425\"
Min-SE: 35
X-AccountId: ACxxxxxxxxxxxxxxxxxxxx
------=_Part_1253_283419664.1674116473425
Content-Type: application/sdp
v=0
o=root 1176539620 1176539620 IN IP4 172.18.x.x
s=provider Media Gateway
c=IN IP4 84.172.x.x
t=0 0
m=audio 15352 RTP/SAVP 0 8 101
a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:<Encryption_key>
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-16
a=ptime:20
a=maxptime:20
a=sendonly
a=label:inbound
m=audio 16022 RTP/SAVP 0 8 101
a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:<Encryption_key>
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-16
a=ptime:20
a=maxptime:20
a=sendonly
a=label:outbound
------=_Part_1253_283419664.1674116473425
Content-Type: application/rs-metadata+xml
Content-Disposition: recording-session
<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<recording xmlns='urn:ietf:params:xml:ns:recording:1'>
<datamode>complete</datamode>
<session session_id=\"Wd/putWgTWCW2z1lI5Db9w==\">
<ExtensionParameters xmlns=\"http://provider.com/siprec\">
<Parameter name=\"Role\" value=\"inbound\"/>
<Parameter name=\"CallerDisplayName\" value=\"Kiana Anderson\"/>
<Parameter name=\"CalleeDisplayName\" value=\"Tomas Richardson\"/>
</ExtensionParameters>
</session>
<participant participant_id=\"bXCloPcETS6P/kfeeJtiow==\">
<nameID aor=\"EE5C7EF0\"/>
</participant>
<participant participant_id=\"3nPi8XzBSzWrtSLlkU8Gjw==\">
<nameID aor=\"230908\"/>
</participant>
<stream stream_id=\"9xff8FcdRUaJCSTxWFbV9g==\" session_id=\"Wd/putWgTWCW2z1lI5Db9w==\"><label>inbound</label></stream>
<stream stream_id=\"f/Qezx4jTMqiWSB1vW7oJA==\" session_id=\"Wd/putWgTWCW2z1lI5Db9w==\"><label>outbound</label></stream>
<sessionrecordingassoc session_id=\"Wd/putWgTWCW2z1lI5Db9w==\">
<associate-time>2023-01-19T08:21:13.382512Z</associate-time>
</sessionrecordingassoc>
<participantsessionassoc participant_id=\"bXCloPcETS6P/kfeeJtiow==\" session_id=\"Wd/putWgTWCW2z1lI5Db9w==\">
<associate-time>2023-01-19T08:21:13.382512Z</associate-time>
</participantsessionassoc>
<participantsessionassoc participant_id=\"3nPi8XzBSzWrtSLlkU8Gjw==\" session_id=\"Wd/putWgTWCW2z1lI5Db9w==\">
<associate-time>2023-01-19T08:21:13.382512Z</associate-time>
</participantsessionassoc>
<participantstreamassoc participant_id=\"bXCloPcETS6P/kfeeJtiow==\">
<send>9xff8FcdRUaJCSTxWFbV9g==</send>
<recv>f/Qezx4jTMqiWSB1vW7oJA==</recv>
</participantstreamassoc>
<participantstreamassoc participant_id=\"3nPi8XzBSzWrtSLlkU8Gjw==\">
<send>f/Qezx4jTMqiWSB1vW7oJA==</send>
<recv>9xff8FcdRUaJCSTxWFbV9g==</recv>
</participantstreamassoc>
</recording>
------=_Part_1253_283419664.1674116473425--
BYE message:
BYE sip:SRS@media.recording.dynamics.com:5061;transport=tls SIP/2.0
Via: SIP/2.0/TLS 84.172.x.x:5061;branch=z9hG4bK1fa2.d03c36b567136fcfae84281e926cda62.0;received=172.16.x.x;rport=40334
Via: SIP/2.0/UDP 172.25.x.x:5060;rport=5060;received=84.144.x.x;branch=z9hG4bK917ce574-0345-4c3d-9b63-d98c2c57dbe6_c3356d0b_600-2513288074170844985
To: <sip:SRS@media.recording.dynamics.com:5061;transport=tls>;tag=OXFWHPJQTL
From: <sip:SRC@sip.provider.com>;tag=66790678_c3356d0b_917ce574-0345-4c3d-9b63-d98c2c57dbe6
Call-ID: efab0870bc597cb3fb56010921e2f57f
CSeq: 2 BYE
Max-Forwards: 68
User-Agent: provider Gateway
Require: siprec
Content-Length: 901
Content-Type: multipart/mixed;boundary=\"----=_Part_29418_1017575873.1674116842924\"
X-AccountId: ACxxxxxxxxxxxxx
Recorder endpoints and regions supported
The following table lists the supported recorder endpoints and their regions. You can configure the recorders you want to use in your telephony provider settings. To learn about how this is done for Twilio Flex, see Step 2: Install the SIPREC connector and route the calls to Dynamics 365.
Endpoint | Region |
---|---|
media.recording.dynamics.com | Global (closest region) |
southeastasia.media.recording.dynamics.com | Southeast Asia |
australiaeast.media.recording.dynamics.com | Australia |
sam.media.recording.dynamics.com | South America |
canadacentral.media.recording.dynamics.com | Canada |
switzerlandnorth.media.recording.dynamics.com | Switzerland |
eastus.media.recording.dynamics.com | US |
francecentral.media.recording.dynamics.com | France |
centralindia.media.recording.dynamics.com | India |
japaneast.media.recording.dynamics.com | Japan |
uae.media.recording.dynamics.com | UAE |
uksouth.media.recording.dynamics.com | UK |
westeurope.media.recording.dynamics.com | West Europe |
zaf.media.recording.dynamics.com | South Africa |
Step 3: Send real-time events (Dialer's client Integration)
To allow conversation intelligence to provide real-time transcription and insights, the third-party dialer can use two events to notify when a call starts or ends.
Call started event: When conversation intelligence gets the "call started" event,it will show the recording button and the real-time transcription and insights.
Call ended event: When conversation intelligence gets the "call ended" event, it will wrap up the call and show the Full summary button to get the AI-generated call summary and insights.
To send the events, use the raiseEvent API in Dynamics 365 Channel Integration Framework (CIF).
Here's a sample code snippet to send the events:
export interface CallStartedEvent {
callId: string;
startTime: Date;
isIncomingCall: boolean;
contactNumber: string;
contactName: string;
}
export interface CallEndedEvent {
callId: string;
callDurationInSeconds: number;
callTerminationReason: string; // ['success', 'error']
callEndTime: Date;
isCallStarted: boolean;
}
dialer.Actions.addListener('onCallStarted', (payload: any) => {
const callStartedEvent : CallStartedEvent = {
callId: payload.call_sid,
startTime: new Date(),
isIncomingCall: payload.attributes.is_incoming_call,
contactName: payload.attributes.caller_name,
contactNumber: payload.attributes.caller_phone_number
};
// @ts-ignore
Microsoft.CIFramework.raiseEvent('WIDGET_CALL_STARTED', callStartedEvent);
});
dialer.Actions.addListener('onCallEnded', (payload: any) => {
const callEndedEvent : CallEndedEvent = {
callId: payload.call_sid,
callEndTime: new Date(),
callTerminationReason: 'success',
isCallStarted: true,
callDurationInSeconds: payload.attributes.call_length
};
// @ts-ignore
Microsoft.CIFramework.raiseEvent('WIDGET_CALL_ENDED', callEndedEvent);
});
Test the integration
After registering the new provider with the tenant and setting up the SIPREC forking and the client dialer events, you can test the integration by creating a new recording policy with the new provider.
Log in as a System administrator in the Sales Hub app.
From Change area, select Sales insights settings.
Go to Global settings > Conversation intelligence. In the Call providers section, you'll see the third-party provider that you've registered.
Create a recording policy for the new provider. For more information, see Set up Microsoft Teams for conversation intelligence
The following screenshot is an example of a recording policy for Twilio.
Now, call a user who is part of the selected security role (in our example, the policy is enabled for all security roles).
When Dynamics 365 receives the callStarted event from the dialer, you'll have the option to start the recording:
After selecting Record, you'll be able to see the real-time transcription during the call and a full summary and call insights at the end of the call.