Integrating with Microsoft Teams
OpenFin’s Microsoft 365 integration API includes functionality specifically for integrating your OpenFin app with Microsoft Teams. This functionality includes:
-
Navigating users to existing Teams conversations (both group conversations and Teams Channel conversations)
-
Starting chats and calls
-
Enabling OpenFin Interop to work "out of the box" with Teams
-
Sharing Instrument context to a Teams conversation
Note
The rest of this article assumes that your app is connected to Microsoft 365 as described in Microsoft 365 integration.
Create a Teams connection
Before you are able to call Teams-specific functionality provided by the API, you must create a new TeamsConnection
object:
import { TeamsConnection } from '@openfin/microsoft365';
const useMsTeamsProtocol = true; // Optional, if true will use msteams: protocol to open links directly in the Teams app instead of via web browser (defaults to true)
const teamsConnection = new TeamsConnection(ms365Connection, useMsTeamsProtocol);
Teams deep linking
The API makes use of Teams deep linking to automate some features of the native Teams desktop application. Deep linking is provided with the msteams
protocol (the integration default) or alternatively via a standard https
link.
The msteams
protocol is preferred if you can assume that the native Teams app is installed on users' desktops, because it provides a seamless Teams user experience. Otherwise, a web page opens in the user's default browser, interrupting the user flow, which in addition to directing the Teams app to the correct function (if installed), also provides the user with options to use the Teams web app or download the native app.
Usage
Make a call or start a chat in Teams from OpenFin
The API provides the option of making a call or starting a chat in Teams in either of the following ways:
-
Calling the API functions (
startChat
orstartCall
) directly -
Calling
registerIntentHandlers
and then raisingStartChat
orStartCall
intents via the OpenFin Interop APIs or FDC3 APIs
Start a group chat by calling startChat
with a list of email addresses of users who should be included in the group chat:
import { GroupChatOptions } from '@openfin/microsoft365';
const startGroupChatOptions: GroupChatOptions = {
emailAddresses: ['[email protected]', '[email protected]'],
topicName: 'New Topic', // Optional, name for the group chat
message: 'Let’s chat about something...', // Optional, text to prefill message field with
};
const resolvedUsersForChat = await teamsConnection.startChat(startGroupChatOptions);
Note
Add emails to Microsoft Entra ID (formerly Azure Active Directory) user accounts.
The Microsoft 365 integration API attempts to resolve any provided email addresses to Microsoft Entra ID users. We recommend that all Microsoft Entra ID users have email addresses defined for best user experience. If an email address can't be resolved to an Entra user, no error is thrown.
Start a channel chat by calling startChat
with the IDs of the team and (optionally) the channel to start the chat with. These ID values would typically be known ahead of time, or alternatively can be discovered by executing a request to the Graph API:
import { ChannelChatOptions } from '@openfin/microsoft365';
const startChannelChatOptions: ChannelChatOptions = {
teamId: 'fbe2bf47-16c8-47cf-b4a5-4b9b187c508b',
channelId: '19:[email protected]', // Optional, if not provided will use team’s primary channel
};
const resolvedTeamChannelForChat = await teamsConnection.startChat(startChannelChatOptions);
);
Start a Teams call by calling startCall
with a list of email addresses of users who should be included in the call. By default, the caller’s camera is turned off when making the call, but can be turned on by default by setting the second parameter to true
:
const emailAddresses = ['[email protected]', '[email protected]'];
// Make a video call
const withVideo = true;
const resolvedUsersForVideoCall = await teamsConnection.startCall(
emailAddresses,
withVideo // Optional, defaults to false
);
// Make an audio call
const resolvedUsersForAudioCall = await teamsConnection.startCall(emailAddresses);
All of the above functions return a Promise that resolves to one of the following:
-
For group chats or calls, to an array of
UserResult
objects in the same order as their matching email addresses were provided. If a user is not found for an email address,undefined
is returned instead of the object. -
For channel chats, to a
TeamChannelResult
object for the resolved Team and Channel.
If no email addresses can be resolved to UserResult
objects, or if no team or channel can be resolved to a TeamChannelResult
object, no error is thrown and the function resolves with an empty value.
Work with Interop/FDC3
Register intent handlers for StartChat
or StartCall
intents:
// Register StartChat and StartCall intent handlers for Teams
const teamsIntentHandlerRegistration = await teamsConnection.registerIntentHandlers();
// Trigger the handler by firing a StartChat or StartCall intent
await fin.me.interop.fireIntent({
name: 'StartChat', // or StartCall
context: {
type: 'fdc3.contactList',
contacts: [
{
type: 'fdc3.contact',
id: {
email: '[email protected]',
},
},
{
type: 'fdc3.contact',
id: {
email: '[email protected]',
},
},
],
},
});
// Unsubscribe intent handlers if intent handling is no longer required
await teamsIntentHandlerRegistration.unsubscribe();
Share instrument contexts to Teams conversations
The API provides the ability to share financial context data to a Teams chat, resulting in a formatted card being posted that allows users in the chat to send the message data to other OpenFin apps via Interop.
The share
function is able to share either an instrument with price info:
or a chart image:
When the share
function is called, here's what happens:
-
Sharer’s desktop: Sharer posts a message to the recipient(s) providing the (hidden) context data in the message payload. The shared information is displayed with a button that fires an intent when clicked. If a chart image was shared, the button fires a ViewChart FDC3 intent, otherwise a ViewInstrument FDC3 intent is fired.
-
Recipient’s desktop: Receives message from sharer. When the button is clicked in the message card, a URL is opened in the user's default web browser that attempts to run (or if already running, focus on) the app that originally shared the message. At this point, the app fires the relevant intent via Interop.
Note
Allow OpenFin "start" links.
For the button action from the Teams message to work, your client must allow internal access to
https://start.openfin.co
from the default web browser. When the user clicks the button, the app that calls theshare
function must already be running, or have access to the URL for the app's manifest so the app can be launched.
The process:
-
Specify the target to share to.
To share to a group chat, provide an array of email addresses, or to share to a Team Channel, provide an object of typeTeamChannelTarget
:import { TeamChannelTarget } from '@openfin/microsoft365'; let target: string[] | TeamChannelTarget; // Share to group chat target = ['[email protected]', '[email protected]']; // Or, share to team channel target = { teamId: 'fbe2bf47-16c8-47cf-b4a5-4b9b187c508b', channelId: '19:[email protected]', // Optional, if not provided will share to the team’s primary channel } as TeamChannelTarget;
-
Specify the financial instrument context data to share in the form of an FDC3 instrument context which must include the
id.ticker
value at a minimum and ideallyname
also (if required, you may also include additional properties and metadata to support your workflows):import * as fdc3 from '@finos/fdc3'; const context: fdc3.Instrument = { type: 'fdc3.instrument', name: 'Microsoft Corporation', id: { ticker: 'MSFT', }, };
-
Create the options object to provide to the share function. To share a chart, specify an object of type
ShareChartOptions
. To share instrument price information, specify an object of typeShareInstrumentOptions
:import { ShareChartOptions, ShareInstrumentOptions } from '@openfin/microsoft365'; let shareOptions: ShareChartOptions | ShareInstrumentOptions; // When sharing a chart shareOptions = { chartImage: new Blob([blobArrayBuffer], { type: 'image/png' }), // blobArrayBuffer would be a byte array containing the chart image data. Supported image types: gif, jpg, png context, target, showMessage: true, // Optional, show message in Teams app after posting, defaults to true timestamp: Date.now(), // Optional, date will not be displayed with chart if not provided } as ShareChartOptions; // Or, when sharing instrument price info shareOptions = { context, priceCurrent: 128.95, // Instrument current price priceHigh: 129.43, // Optional, instrument session high price priceLow: 127.25, // Optional, instrument session low price priceOpen: 127.42, // Optional, instrument session open price showMessage: true, // Optional, show message in Teams app after posting, defaults to true target, timestamp: Date.now(), // Optional, defaults to now } as ShareInstrumentOptions;
-
Call the
share
function with the specified options:const resolvedShareTarget = await teamsConnection.share(shareOptions);
The share
function returns a Promise that resolves to either a TeamChannelResult
object or an array of UserResult
objects, depending on the target
specified. As with startChat
and startCall
, no error is thrown if the specified target cannot be resolved.
Updated 5 months ago