Send in-app notifications within model-driven apps
Article
Developers of model-driven apps can configure notifications to be displayed to app users as a toast or within the notification center. Your model-driven app automatically polls the system for new notifications and displays them to the user. The notification sender or your system administrator can configure how the notification is shown and how it can be dismissed. Notifications appear in the notification center until the recipient dismisses them or they expire. By default, a notification expires after 14 days but your administrator can override this setting.
Notifications are user-specific. Each notification is intended for a single user, identified as the recipient when the notification is sent. Sending a notification to a team isn't supported. If you need to send notifications to multiple users, you must create notifications for each individual user.
This article outlines the steps for how to send in-app notifications to a specific user. To see how these notifications appear in applications, see In-app notifications in model-driven apps.
Enable the in-app notification feature
To use the in-app notification feature, you need to enable the In-app notifications setting. This setting is stored within the model-driven app.
The SendAppNotification message doesn't currently have request and response classes in the Dataverse SDK for .NET. To get strongly typed classes for this message, you must generate classes or use the underlying OrganizationRequest and OrganizationResponse classes. More information: Use messages with the SDK for .NET.
The SendAppNotification message uses open types, enabling dynamic properties on the in-app notification. For example, a notification can have zero to many actions, and each action may have different action types. Open types enable having dynamic properties for the actions depending on the action types selected. More information: Use open types with custom APIs
The following basic examples show how to use the API to send in-app notifications.
var SendAppNotificationRequest = new Example.SendAppNotificationRequest(
title = "Welcome",
recipient = "/systemusers(<GUID of the user>)",
body = "Welcome to the world of app notifications!",
priority = 200000000,
iconType = 100000000,
toastType = 200000000,
);
Xrm.WebApi.online.execute(SendAppNotificationRequest).then(function (response) {
if (response.ok) {
console.log("Status: %s %s", response.status, response.statusText);
return response.json();
}
})
.then(function (responseBody) {
console.log("Response Body: %s", responseBody.NotificationId);
})
.catch(function (error) {
console.log(error.message);
});
Request:
POST [Organization URI]/api/data/v9.2/SendAppNotification
Content-Type: application/json; charset=utf-8
OData-MaxVersion: 4.0
OData-Version: 4.0
Accept: application/json
{
"Title": "Welcome",
"Body": "Welcome to the world of app notifications!",
"Recipient": "/systemusers(<Guid of the user>)",
"IconType": 100000000, // info
"ToastType": 200000000 // timed
}
/// <summary>
/// Example of SendAppNotification
/// </summary>
/// <param name="service">Authenticated client implementing the IOrganizationService interface</param>
/// <param name="userId">The Id of the user to send the notification to.</param>
/// <returns>The app notification id</returns>
public static Guid SendAppNotificationExample(IOrganizationService service, Guid userId)
{
var request = new OrganizationRequest()
{
RequestName = "SendAppNotification",
Parameters = new ParameterCollection
{
["Title"] = "Welcome",
["Recipient"] = new EntityReference("systemuser", userId),
["Body"] = "Welcome to the world of app notifications!",
["IconType"] = new OptionSetValue(100000000), //info
["ToastType"] = new OptionSetValue(200000000) //timed
}
};
OrganizationResponse response = service.Execute(request);
return (Guid)response.Results["NotificationId"];
}
In-app notifications use polling to retrieve notifications periodically when the app is running. New notifications are retrieved at start of the model-driven app and when a page navigation occurs as long as the last retrieval is more than one minute ago. If a user stays on a page for a long duration, new notifications aren't retrieved until the user navigates to another page.
The user who receives the notification. While this column can be set to either a user or team, you must only set this to a user. The notification can't be set to a team.
Body
Body
Details about the notification.
IconType
IconType
The list of predefined icons. The default value is Info. For more information, go to Changing the notification icon later in this article.
Toast Type
ToastType
The list of notification behaviors. The default value is Timed. For more information, go to Changing the notification behavior later in this article.
Priority
Priority
Enables prioritization of notifications, which determines the order in which the notifications are displayed in the notification center. For more information, see Changing the notification behavior later in this article.
Expiry (seconds)
TTLInSeconds
The number of seconds from when the notification should be deleted if not already dismissed.
Data
Data
JSON that's used for extensibility and parsing richer data into the notification. The maximum length is 5,000 characters.
Note
The appmoduleid field is not used in the table.
Customizing the notification
In addition to the basic properties of the notification, you have options for customizing the notification delivered to the user. Customizing the notification involves changing the styles in the Title and Body of the notification, customizing the notification icon, and changing the behavior of the notification.
Using markdown in Title and Body
The Title and Body parameters of the SendAppNotification message don't support markdown defined within the properties. You can adjust the styles of these properties using markdown in the OverrideContent property. This field supports overriding the Title and Body simple strings with a limited subset of markdown styles.
The following is the supported markdown.
Text Style
Markdown
Bold
**Bold**
Italic
_Italic_
Bullet list
- Item 1\r- Item 2\r- Item 3
Numbered list
1. Green\r2. Orange\r3. Blue
Hyperlinks
[Title](url)
Newlines can be included with the body using \n\n\n\n.
This example shows how to create a notification by adding a custom body definition that includes an inline link.
var SendAppNotificationRequest = new Example.SendAppNotificationRequest(title = "SLA critical",
recipient = "/systemusers(<GUID of the user>)",
body = "Record assigned to you is critically past SLA.",
iconType = 100000003,
toastType = 200000000,
overrideContent = {
"@odata.type": "#Microsoft.Dynamics.CRM.expando",
"title": "**SLA critical**",
"body": "Case record [Complete overhaul required (sample)](?pagetype=entityrecord&etn=incident&id=0a9f62a8-90df-e311-9565-a45d36fc5fe8) assigned is critically past SLA and has been escalated to your manager."
}
);
Xrm.WebApi.online.execute(SendAppNotificationRequest).then(function (response) {
if (response.ok) {
console.log("Status: %s %s", response.status, response.statusText);
return response.json();
}
})
.then(function (responseBody) {
console.log("Response Body: %s", responseBody.NotificationId);
})
.catch(function (error) {
console.log(error.message);
});
POST [Organization URI]/api/data/v9.2/SendAppNotification
Content-Type: application/json; charset=utf-8
OData-MaxVersion: 4.0
OData-Version: 4.0
Accept: application/json
{
"Title": "SLA critical",
"Body": "Record assigned to you is critically past SLA.",
"Recipient": "/systemusers(<Guid of the user>)",
"IconType": 100000003, // warning
"ToastType": 200000000, // timed
"OverrideContent": {
"@odata.type": "#Microsoft.Dynamics.CRM.expando",
"title": "**SLA critical**",
"body": "Case record [Complete overhaul required (sample)](?pagetype=entityrecord&etn=incident&id=0a9f62a8-90df-e311-9565-a45d36fc5fe8) assigned is critically past SLA and has been escalated to your manager."
}
}
/// <summary>
/// Example of SendAppNotification with overridden content
/// </summary>
/// <param name="service">Authenticated client implementing the IOrganizationService interface</param>
/// <param name="userId">The Id of the user to send the notification to.</param>
/// <returns>The app notification id</returns>
public static Guid SendAppNotificationWithOveriddenContent(IOrganizationService service, Guid userId)
{
var request = new OrganizationRequest()
{
RequestName = "SendAppNotification",
Parameters = new ParameterCollection
{
["Title"] = "SLA critical",
["Recipient"] = new EntityReference("systemuser", userId),
["Body"] = "Record assigned to you is critically past SLA.",
["IconType"] = new OptionSetValue(100000003), //warning
["ToastType"] = new OptionSetValue(200000000), //timed
["OverrideContent"] = new Entity()
{
Attributes =
{
["title"] = "**SLA critical**",
["body"] = "Case record [Complete overhaul required (sample)](?pagetype=entityrecord&etn=incident&id=0a9f62a8-90df-e311-9565-a45d36fc5fe8) assigned to you is critically past SLA and has been escalated to your manager."
}
}
}
};
OrganizationResponse response = service.Execute(request);
return (Guid)response.Results["NotificationId"];
}
This example adds a custom title and a body definition that allows multiple links, bold formatting, and italic formatting.
var SendAppNotificationRequest = new Example.SendAppNotificationRequest(title = "Complete overhaul required (sample)",
recipient = "/systemusers(<GUID of the user>)",
body = "Maria Campbell mentioned you in a post.",
priority = 200000000,
iconType = 100000004,
toastType = 200000000,
expiry = 120000,
overrideContent = {
"@odata.type": "#Microsoft.Dynamics.CRM.expando",
"title": "[Complete overhaul required (sample)](?pagetype=entityrecord&etn=incident&id=0a9f62a8-90df-e311-9565-a45d36fc5fe8)",
"body": "[Maria Campbell](?pagetype=entityrecord&etn=contact&id=43m770h2-6567-ebm1-ob2b-000d3ac3kd6c) mentioned you in a post: _\"**[@Paul](?pagetype=entityrecord&etn=contact&id=03f770b2-6567-eb11-bb2b-000d3ac2be4d)** we need to prioritize this overdue case, [@Robert](?pagetype=entityrecord&etn=contact&id=73f970b2-6567-eb11-bb2b-000d3ac2se4h) will work with you to engage with engineering team ASAP.\"_"
}
);
// Use the request object to execute the function
Xrm.WebApi.online.execute(SendAppNotificationRequest).then(function (response) {
if (response.ok) {
console.log("Status: %s %s", response.status, response.statusText);
// Use response.json() to access the content of the response body.
return response.json();
}
})
.then(function (responseBody) {
console.log("Response Body: %s", responseBody.NotificationId);
})
.catch(function (error) {
console.log(error.message);
// handle error conditions
});
Request:
POST [Organization URI]/api/data/v9.2/SendAppNotification
Content-Type: application/json; charset=utf-8
OData-MaxVersion: 4.0
OData-Version: 4.0
Accept: application/json
{
"Title": "Complete overhaul required (sample)",
"Body": "Maria Campbell mentioned you in a post.",
"Recipient": "/systemusers(<Guid of the user>)",
"IconType": 100000004, // mention
"OverrideContent": {
"@odata.type": "#Microsoft.Dynamics.CRM.expando",
"title": "[Complete overhaul required (sample)](?pagetype=entityrecord&etn=incident&id=0a9f62a8-90df-e311-9565-a45d36fc5fe8)",
"body": "[Maria Campbell](?pagetype=entityrecord&etn=contact&id=43m770h2-6567-ebm1-ob2b-000d3ac3kd6c) mentioned you in a post: _\"**[@Paul](?pagetype=entityrecord&etn=contact&id=03f770b2-6567-eb11-bb2b-000d3ac2be4d)** we need to prioritize this overdue case, [@Robert](?pagetype=entityrecord&etn=contact&id=73f970b2-6567-eb11-bb2b-000d3ac2se4h) will work with you to engage with engineering team ASAP.\"_"
}
}
Response:
HTTP/1.1 204 No Content
OData-Version: 4.0
/// <summary>
/// Example of SendAppNotification with formatted content
/// </summary>
/// <param name="service">Authenticated client implementing the IOrganizationService interface</param>
/// <param name="userId">The Id of the user to send the notification to.</param>
/// <returns>The app notification id</returns>
public static Guid SendAppNotificationWithFormattedContent(IOrganizationService service, Guid userId)
{
var request = new OrganizationRequest()
{
RequestName = "SendAppNotification",
Parameters = new ParameterCollection
{
["Title"] = "Complete overhaul required (sample)",
["Recipient"] = new EntityReference("systemuser", userId),
["Body"] = "Maria Campbell mentioned you in a post.",
["IconType"] = new OptionSetValue(100000004), //mention
["OverrideContent"] = new Entity()
{
Attributes =
{
["title"] = "[Complete overhaul required (sample)](?pagetype=entityrecord&etn=incident&id=0a9f62a8-90df-e311-9565-a45d36fc5fe8)",
["body"] = "[Maria Campbell](?pagetype=entityrecord&etn=contact&id=43m770h2-6567-ebm1-ob2b-000d3ac3kd6c) mentioned you in a post: _\"**[@Paul](?pagetype=entityrecord&etn=contact&id=03f770b2-6567-eb11-bb2b-000d3ac2be4d)** we need to prioritize this overdue case, [@Robert](?pagetype=entityrecord&etn=contact&id=73f970b2-6567-eb11-bb2b-000d3ac2se4h) will work with you to engage with engineering team ASAP.\"_"
}
}
}
};
OrganizationResponse response = service.Execute(request);
return (Guid)response.Results["NotificationId"];
}
Note
OverrideContent is not supported in Power Fx with the xSendAppNotification function.
Changing the notification behavior
You can change in-app notification behavior by setting ToastType to one of the following values.
Toast Type
Behavior
Value
Timed
The notification appears for a brief duration (the default is four seconds) and then disappears.
200000000
Hidden
The notification appears only in the notification center and not as a toast notification.
200000001
Changing the notification icon
You can change the in-app notification icon by setting IconType to one of the following values. When using a custom icon, specify the iconUrl parameter within the OverrideContent parameter.
Icon Type
Value
Image
Info
100000000
Success
100000001
Failure
100000002
Warning
100000003
Mention
100000004
Custom
100000005
The following example demonstrates using Web API to send a notification with a custom icon.
POST [Organization URI]/api/data/v9.2/SendAppNotification
HTTP/1.1
Content-Type: application/json; charset=utf-8
OData-MaxVersion: 4.0
OData-Version: 4.0
Accept: application/json
{
"Title": "Welcome",
"Body": "Welcome to the world of app notifications!",
"Recipient": "/systemusers(<Guid of the user>)",
"IconType": 100000005, // custom
"OverrideContent": {
"@odata.type": "#Microsoft.Dynamics.CRM.expando",
"iconUrl": "/WebResources/cr245_AlertOn" //URL of the image file to be used for the notification icon
}
}
Setting the notification priority
You can change the order in which notifications display in the notification center by setting the Priority. The following are the optional values:
Priority
Value
Normal
200000000
High
200000001
The default value is Normal. Notifications are sorted in the notification center by Priority and Created On date, descending. High priority notifications display at the top of the list in the notification center.
Notification actions
In-app notifications support zero to many actions on the notification card. There are three supported action types:
URL: When the action is selected the web browser navigates to the defined URL.
Side Pane: When the action is selected, a side pane is opened in the app and loads the defined context in the pane.
Teams Chat: When the action is selected, a Teams chat is initiated with defined users in the context of a Dynamics 365 record.
Defining a URL action
The URL action type enables navigation from the action on the app notification to a defined URL. The following are the parameters for this action type:
Parameter
Required
Data type
Description
url
Yes
String
The URL of the web address to be opened when the action is selected.
navigationTarget
No
String
This parameter controls where a navigation link opens. The options are:
dialog: Opens in the center dialog.
inline: Default. Opens in the current page.
newWindow: Opens in a new browser tab.
The following example shows how to create a notification with a single URL action.
var SendAppNotificationRequest = new Example.SendAppNotificationRequest(title = "Congratulations",
recipient = "/systemusers(<GUID of the user>)",
body = "Your customer rating is now an A. You resolved 80% of your cases within SLA thi week and average customer rating was A+",
iconType = 100000001,
toastType = 200000000,
overrideContent = {
"@odata.type": "#Microsoft.Dynamics.CRM.expando",
"title": "**SLA critical**",
"body": "Case record [Complete overhaul required (sample)](?pagetype=entityrecord&etn=incident&id=0a9f62a8-90df-e311-9565-a45d36fc5fe8) assigned is critically past SLA and has been escalated to your manager."
},
actions = {
"@odata.type": "Microsoft.Dynamics.CRM.expando",
"actions@odata.type": "#Collection(Microsoft.Dynamics.CRM.expando)",
"actions": [
{
"title": "View cases",
"data": {
"@odata.type": "#Microsoft.Dynamics.CRM.expando",
"type": "url",
"url": "?pagetype=entitylist&etn=incident&viewid=00000000-0000-0000-00aa-000010001028&viewType=1039",
"navigationTarget": "newWindow"
}
}
]
}
);
Xrm.WebApi.online.execute(SendAppNotificationRequest).then(function (response) {
if (response.ok) {
console.log("Status: %s %s", response.status, response.statusText);
return response.json();
}
})
.then(function (responseBody) {
console.log("Response Body: %s", responseBody.NotificationId);
})
.catch(function (error) {
console.log(error.message);
});
POST [Organization URI]/api/data/v9.2/SendAppNotification
Content-Type: application/json; charset=utf-8
OData-MaxVersion: 4.0
OData-Version: 4.0
Accept: application/json
{
"Title": "Congratulations",
"Body": "Your customer rating is now an A. You resolved 80% of your cases within SLA thi week and average customer rating was A+",
"Recipient": "/systemusers(<GUID of user>)",
"IconType": 100000001, // success
"ToastType": 200000000, // timed
"Actions": {
"@odata.type":"Microsoft.Dynamics.CRM.expando",
"actions@odata.type":"#Collection(Microsoft.Dynamics.CRM.expando)",
"actions": [
{
"title": "View cases",
"data": {
"@odata.type": "#Microsoft.Dynamics.CRM.expando",
"type": "url",
"url": "?pagetype=entitylist&etn=incident&viewid=00000000-0000-0000-00aa-000010001028&viewType=1039",
"navigationTarget": "newWindow"
}
}
]
}
}
/// <summary>
/// Example of SendAppNotification with URl Action
/// </summary>
/// <param name="service">Authenticated client implementing the IOrganizationService interface</param>
/// <param name="userId">The Id of the user to send the notification to.</param>
/// <returns>The app notification id</returns>
public static Guid SendAppNotificationWithUrlAction(IOrganizationService service, Guid userId)
{
var request = new OrganizationRequest()
{
RequestName = "SendAppNotification",
Parameters = new ParameterCollection
{
["Title"] = "Congratulations",
["Recipient"] = new EntityReference("systemuser", userId),
["Body"] = "Your customer rating is now an A. You resolved 80% of your cases within SLA thi week and average customer rating was A+",
["IconType"] = new OptionSetValue(100000000), //info
["ToastType"] = new OptionSetValue(200000000), //timed
["Actions"] = new Entity()
{
Attributes =
{
["actions"] = new EntityCollection()
{
Entities =
{
new Entity()
{
Attributes =
{
["title"] = "View cases",
["data"] = new Entity()
{
Attributes =
{
["type"] = "url",
["url"] = "?pagetype=entitylist&etn=incident&viewid=00000000-0000-0000-00aa-000010001028&viewType=1039",
["navigationTarget"] = "newWindow"
}
}
}
}
}
}
}
}
}
};
Defining a side pane action
A side pane action enables opening a side pane to load a defined page when the action is selected from the app notification. More information: Creating side panes by using a client API for more information.
When using the side pane action type, you have control over the options of the side pane itself, and the page that loads in the side pane.
See createPane for the optional parameters for the pane that is created.
var SendAppNotificationRequest = new Example.SendAppNotificationRequest(title = "New task",
recipient = "/systemusers(<GUID of the user>)",
body = "A new task has been assigned to you to follow up on the Contoso account",
iconType = 100000000,
toastType = 200000000,
actions = {
"@odata.type": "Microsoft.Dynamics.CRM.expando",
"actions@odata.type": "#Collection(Microsoft.Dynamics.CRM.expando)",
"actions": [
{
"title": "View task",
"data": {
"@odata.type": "#Microsoft.Dynamics.CRM.expando",
"type": "sidepane",
"paneOptions": {
"@odata.type": "#Microsoft.Dynamics.CRM.expando",
"title": "Task Record",
"width": 400
},
"navigationTarget": {
"@odata.type": "#Microsoft.Dynamics.CRM.expando",
"pageType": "entityrecord",
"entityName": "task",
"entityId": "<Task ID>"
}
}
}
]
}
);
Xrm.WebApi.online.execute(SendAppNotificationRequest).then(function (response) {
if (response.ok) {
console.log("Status: %s %s", response.status, response.statusText);
return response.json();
}
})
.then(function (responseBody) {
console.log("Response Body: %s", responseBody.NotificationId);
})
.catch(function (error) {
console.log(error.message);
});
POST [Organization URI]/api/data/v9.2/SendAppNotification
Content-Type: application/json; charset=utf-8
OData-MaxVersion: 4.0
OData-Version: 4.0
Accept: application/json
{
"Title": "New task",
"Body": "A new task has been assigned to you to follow up on the Contoso account",
"Recipient": "/systemusers(<User ID>)",
"IconType": 100000000, // info
"ToastType": 200000000, // timed
"Actions": {
"@odata.type":"Microsoft.Dynamics.CRM.expando",
"actions@odata.type":"#Collection(Microsoft.Dynamics.CRM.expando)",
"actions": [
{
"title": "View task",
"data" : {
"@odata.type": "#Microsoft.Dynamics.CRM.expando",
"type": "sidepane",
"paneOptions": {
"@odata.type": "#Microsoft.Dynamics.CRM.expando",
"title": "Task Record",
"width": 400
},
"navigationTarget": {
"@odata.type": "#Microsoft.Dynamics.CRM.expando",
"pageType": "entityrecord",
"entityName": "task",
"entityId": "<Task ID>"
}
}
},
{
"title": "View account",
"data" : {
"@odata.type": "#Microsoft.Dynamics.CRM.expando",
"type": "sidepane",
"paneOptions": {
"@odata.type": "#Microsoft.Dynamics.CRM.expando",
"title": "Account Record",
"width": 400
},
"navigationTarget": {
"@odata.type": "#Microsoft.Dynamics.CRM.expando",
"pageType": "entityrecord",
"entityName": "account",
"entityId": "<Account ID>"
}
}
}
]
}
}
/// <summary>
/// Example of SendAppNotification with side pane actions
/// </summary>
/// <param name="service">Authenticated client implementing the IOrganizationService interface</param>
/// <param name="userId">The Id of the user to send the notification to.</param>
/// <returns>The app notification id</returns>
public static Guid SendAppNotificationWithSidePaneActions(IOrganizationService service, Guid userId)
{
var request = new OrganizationRequest()
{
RequestName = "SendAppNotification",
Parameters = new ParameterCollection
{
["Title"] = "New task",
["Recipient"] = new EntityReference("systemuser", userId),
["Body"] = "A new task has been assigned to you to follow up on the Contoso account",
["IconType"] = new OptionSetValue(100000000), //info
["ToastType"] = new OptionSetValue(200000000), //timed
["Actions"] = new Entity()
{
Attributes =
{
["actions"] = new EntityCollection()
{
Entities =
{
new Entity()
{
Attributes =
{
["title"] = "View task",
["data"] = new Entity()
{
Attributes =
{
["type"] = "sidepane",
["paneOptions"] = new Entity
{
Attributes =
{
["title"] = "Task",
["width"] = 400
}
},
["navigationTarget"] = new Entity
{
Attributes =
{
["pageType"] = "entityrecord",
["entityName"] = "task",
["entityId"] = "<GUID of the table record>"
}
}
}
}
}
},
new Entity()
{
Attributes =
{
["title"] = "View account",
["data"] = new Entity()
{
Attributes =
{
["type"] = "sidepane",
["paneOptions"] = new Entity
{
Attributes =
{
["title"] = "Account",
["width"] = 400
}
},
["navigationTarget"] = new Entity
{
Attributes =
{
["pageType"] = "entityrecord",
["entityName"] = "account",
["entityId"] = "<GUID of the table record>"
}
}
}
}
}
}
}
}
}
}
}
};
OrganizationResponse response = service.Execute(request);
return (Guid)response.Results["NotificationId"];
}
Defining a Teams chat action
A Teams chat action enables scenarios where a Teams chat is initiated from the app notification. This action uses the embedded Teams feature for Dynamics 365 apps, which provides sellers and agents the ability to chat in Microsoft Teams from within the customer engagement apps, such as Sales Hub, Customer Service Hub, and custom apps.
Create a new chat session or open an existing chat session.
Link the chat session to a Dynamics 365 record or create an unlinked chat.
The following are the parameters for defining a Teams chat action on the app notification.
Parameter
Data type
Description
chatId
String
Define a value for the chat ID to open an existing chat. This is the ID of the Teams chat session, which can be obtained from the id property of the chat entity in Microsoft Graph. More information: Get chat for more information. For Teams chat sessions that have been linked to Dynamics 365 records, the association is stored in the Microsoft Teams chat association entity (msdyn_teamschatassociation) table in Dataverse. The ID for the chat session is stored in the Teams Chat Id property of this table.
Leave this parameter blank to initiate a new chat session.
memberIds
GUID[]
An array of the Microsoft Entra ID user ID values of each of the participants that to be included in a new chat session. Member ID values shouldn't be defined if a value has been defined for the chatId parameter. If the chatId has been defined, then the existing chat is opened, and the members of the existing chat are included in the chat when opened.
entityContext
Expando
The entity context provides the Dynamics 365 record to which the chat session should be linked. For example, if the chat session is regarding a specific customer account record, define the account record in this parameter to have the chat session linked to the account and display in the account's timeline.
The entity context includes the entityName and recordId parameters, which must be defined to identify the record for the entity context.
An entity context shouldn't be defined if a value has been defined for the chatId parameter. If the chatId has been defined, then the existing chat is opened, and the entityContext, whether linked or unlinked, will already have been defined for the existing chat. If the action is creating a new chat session (that is, the chatId parameter hasn't been provided), and the entity context isn't defined, then the new chat session won't be linked to a Dynamics 365 record.
entityName
String
Part of the entity context, the logical name of the Dataverse table for the record to which the chat is related to.
recordId
GUID
Part of the entity context, this is the ID property of the table defined in the entityName parameter for the record to which the chat will be linked.
chatTitle
String
The title of the Teams chat.
initialMessage
String
The text of an introduction message you may optionally provide that will be automatically sent when the chat is created.
The following example shows creating an app notification with a single Teams chat action. When the action is selected on the toast notification it initiates the chat with the participants defined. The chat is linked to a defined account record.
var SendAppNotificationRequest = new Example.SendAppNotificationRequest(title = "New order posted",
recipient = "/systemusers(<GUID of the user>)",
body = "A new sales order has been posted for Contoso",
iconType = 100000000,
toastType = 200000000,
actions = {
"@odata.type": "Microsoft.Dynamics.CRM.expando",
"actions@odata.type": "#Collection(Microsoft.Dynamics.CRM.expando)",
"actions": [
{
"title": "Chat with sales rep",
"data": {
"@odata.type": "#Microsoft.Dynamics.CRM.expando",
"type": "teamsChat",
"memberIds@odata.type": "#Collection(String)",
"memberIds": ["<Microsoft Entra ID User ID 1>", "<Microsoft Entra ID User ID 2>"],
"entityContext": {
"@odata.type": "#Microsoft.Dynamics.CRM.expando",
"entityName": "account",
"recordId": "<Account ID value>"
}
}
}
]
}
);
Xrm.WebApi.online.execute(SendAppNotificationRequest).then(function (response) {
if (response.ok) {
console.log("Status: %s %s", response.status, response.statusText);
return response.json();
}
})
.then(function (responseBody) {
console.log("Response Body: %s", responseBody.NotificationId);
})
.catch(function (error) {
console.log(error.message);
});
POST [Organization URI]/api/data/v9.2/SendAppNotification
Content-Type: application/json; charset=utf-8
OData-MaxVersion: 4.0
OData-Version: 4.0
Accept: application/json
{
"Title": "New order posted",
"Body": "A new sales order has been posted for Contoso",
"Recipient": "/systemusers(<Guid of the user>)",
"IconType": 100000000, // info
"ToastType": 200000000, // timed
"Actions": {
"@odata.type":"Microsoft.Dynamics.CRM.expando",
"actions@odata.type":"#Collection(Microsoft.Dynamics.CRM.expando)",
"actions": [
{
"title": "Chat with sales rep",
"data": {
"@odata.type":"#Microsoft.Dynamics.CRM.expando",
"type": "teamsChat",
"memberIds@odata.type": "#Collection(String)",
"memberIds": ["<Microsoft Entra ID user ID 1>","<Microsoft Entra ID user ID 2>"],
"entityContext": {
"@odata.type": "#Microsoft.Dynamics.CRM.expando",
"entityName": "account",
"recordId": "<Account ID value>"
}
}
}
]
}
}
/// <summary>
/// Example of SendAppNotification with single Teams chat action.
/// </summary>
/// <param name="service">Authenticated client implementing the IOrganizationService interface</param>
/// <param name="userId">The Id of the user to send the notification to.</param>
/// <param name="userIds">The Ids of the users in the teams chat.</param>
/// <returns>The app notification id</returns>
public static Guid SendAppNotificationWithTeamChatAction(
IOrganizationService service,
Guid userId,
Guid[] userIds)
{
var request = new OrganizationRequest()
{
RequestName = "SendAppNotification",
Parameters = new ParameterCollection
{
["Title"] = "New order posted",
["Recipient"] = new EntityReference("systemuser", userId),
["Body"] = "A new sales order has been posted for Contoso",
["IconType"] = new OptionSetValue(100000000), //info
["ToastType"] = new OptionSetValue(200000000), //timed
["Actions"] = new Entity()
{
Attributes =
{
["actions"] = new EntityCollection()
{
Entities =
{
new Entity()
{
Attributes =
{
["title"] = "Chat with sales rep",
["data"] = new Entity()
{
Attributes =
{
["type"] = "teamsChat",
["memberIds"] = Array.ConvertAll(userIds, x => x.ToString()),
["entityContext"] = new Entity
{
Attributes =
{
["entityName"] = "account",
["recordId"] = "<Account ID value>"
}
}
}
}
}
}
}
}
}
}
}
};
OrganizationResponse response = service.Execute(request);
return (Guid)response.Results["NotificationId"];
}
Creating a function for your client script
The client API examples in this topic provide examples of client scripting to send in-app notifications. The examples call a SendAppNotificationRequest function. To complete the examples, you will need to construct the reusable function in your environment. Below is an example of the function.
The in-app notification feature uses three tables. A user needs to have the correct security roles to receive notifications and to send notifications to themselves or other users.
In addition to the appropriate table permissions, a user must be assigned the Send In-App NotificationprvSendAppNotification privilege to execute the SendAppNotification message. The privilege is granted to the Environment Maker role by default. It isn't required for sending in-app notifications by directly creating appnotification entity records without executing the SendAppNotification message. It isn't required to receive notifications.
Usage
Required table privileges
User has no in-app notification bell and receives no in-app notification
None
User can receive in-app notifications
Basic: Read privilege on the app notification table.
Create, Read, Write, and Append privileges on the model-driven app user setting.
Read and AppendTo privileges on setting definition.
User can send in-app notifications to self
Basic: Create privilege on the app notification table. Additionally, Send In-App Notification privilege is needed if using SendAppNotification message.
User can send in-app notifications to others
Create privilege with Local, Deep, or Global access level on the app notification table based on the receiving user's business unit. Additionally, Send In-App Notification privilege is needed if using SendAppNotification message.
User can delete in-app notifications
Global: Delete privileges on the app notification table.
The Send In-App Notification privilege can be added to a role using the Role Privilege Picker under the Miscellaneous privileges tab.
Notification storage
Because the app notification table uses the organization's database storage capacity, it's important to consider the volume of notifications sent and the expiration setting. More information: Microsoft Dataverse storage capacity
In-app notifications vs. push notifications
The Power Apps Notification connector is for push notifications, which are separate from in-app notification. Push notifications only appear on the mobile device notifications list to open the app. In-app notifications appear when the app is open. We recommend limiting the use of push notifications to high-priority items, to avoid overwhelming the user. For more information, go to:
Demonstrate skills to plan, deploy, configure, and manage Microsoft Teams to focus on efficient and effective collaboration and communication in a Microsoft 365 environment.