title: User Message Types audience: developer keywords: notification, user, send, read, count, thread, message, Cloud Events Note
Parent Document: API_Reference.md Implementation Folder: app/src/Message Type/Implementations/Notification/
User message types provide in-app notification capabilities for Cloud Events integrations. Notifications are stored in the Cloud Events Note table and scoped to individual users. Features include:
All read operations are automatically filtered to the current user (caller identity) via FilterGroup(2).
| Message Type | Direction | Purpose |
|---|---|---|
| User.Notification.Count | Outbound | Get total, unread, and read notification counts |
| User.Notification.Get | Outbound | Retrieve paginated list of notifications |
| User.Notification.Read | Inbound | Mark notifications as read or unread |
| User.Notification.Send | Inbound | Send a new notification to a user |
| User.Notification.Thread | Outbound | Retrieve all notifications in a thread |
| Email.Draft.Set | Inbound | Create an email draft in outbox (HTML + attachments, no send) |
All outbound message types return notification records with this JSON structure:
| Field | Type | Description |
|---|---|---|
entryNo | Integer | Unique entry number |
threadId | GUID | Thread identifier for grouped conversations |
parentEntryNo | Integer | Parent notification entry number (0 if root) |
recipientUserId | Code[50] | Recipient user ID |
senderUserId | Code[50] | Sender user ID |
relatedTableId | Integer | Related BC table ID (0 if none) |
relatedRecordSystemId | GUID | Related BC record SystemId |
approvalEntryNo | Integer | Related approval entry number (0 if none) |
subject | Text[250] | Notification subject line |
body | Text | Notification body text (from Blob field) |
isRead | Boolean | Whether the notification has been read |
sourceEntrySystemId | GUID | SystemId of the source notification entry |
systemId | GUID | SystemId of the notification record |
systemCreatedAt | DateTime | When the notification was created |
systemModifiedAt | DateTime | When the notification was last modified |
notificationType | Text | Notification type enum name |
Table: Cloud Events Note (65327)
| No. | Name | Type | In PK |
|---|---|---|---|
| 1 | Entry No. | Integer | Yes |
| 2 | Thread ID | GUID | No |
| 3 | Parent Entry No. | Integer | No |
| 4 | Recipient User ID | Code[50] | No |
| 5 | Sender User ID | Code[50] | No |
| 6 | Related Table ID | Integer | No |
| 7 | Related Record SystemId | GUID | No |
| 8 | Approval Entry No. | Integer | No |
| 9 | Subject | Text[250] | No |
| 10 | Body | Blob (UTF-8 text) | No |
| 11 | Is Read | Boolean | No |
| 12 | Notification Type | Enum | No |
Recipient User ID = current user via FilterGroup(2).Sender User ID to the current user automatically.Recipient User ID matches the current user.Direction: Outbound (Response to request)
Purpose: Returns the total, unread, and read notification counts for the current user.
{
"specversion": "1.0",
"type": "User.Notification.Count",
"source": "MyApp v1.0"
}
No request data parameters. No subject or data body is required.
| Field | Type | Description |
|---|---|---|
status | String | "Success" or "Error" |
total | Integer | Total notifications for the current user |
unread | Integer | Unread notifications (Is Read = false) |
read | Integer | Read notifications (Is Read = true) |
{
"status": "Success",
"total": 25,
"unread": 10,
"read": 15
}
Direction: Outbound (Response to request)
Purpose: Retrieves a paginated list of notifications for the current user. Supports skip/take paging and optional table view filtering.
{
"specversion": "1.0",
"type": "User.Notification.Get",
"source": "MyApp v1.0",
"data": "{\"skip\":0,\"take\":20}"
}
| Parameter | Type | Required | Description |
|---|---|---|---|
skip | Integer | No | Number of records to skip. Default: 0. |
take | Integer | No | Maximum records to return. Default: 50. |
tableView | String | No | BC table view filter expression. |
{
"skip": 0,
"take": 10,
"tableView": "WHERE(Is Read=CONST(No))"
}
| Field | Type | Description |
|---|---|---|
status | String | "Success" or "Error" |
noOfRecords | Integer | Total records matching filters |
result | Array | Array of notification objects (see Common Structure) |
{
"status": "Success",
"noOfRecords": 2,
"result": [
{
"entryNo": 1,
"threadId": "00000000-0000-0000-0000-000000000000",
"parentEntryNo": 0,
"recipientUserId": "ADMIN",
"senderUserId": "SYSTEM",
"relatedTableId": 0,
"relatedRecordSystemId": "00000000-0000-0000-0000-000000000000",
"approvalEntryNo": 0,
"subject": "New order received",
"body": "Sales order SO-1001 has been created.",
"isRead": false,
"sourceEntrySystemId": "00000000-0000-0000-0000-000000000000",
"systemId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"systemCreatedAt": "2024-01-15T10:30:00Z",
"systemModifiedAt": "2024-01-15T10:30:00Z",
"notificationType": "Message"
}
]
}
FilterGroup(2)tableView for server-side filtering (e.g., unread only, specific notification type)Direction: Inbound (Write operation)
Purpose: Marks one or more notifications as read or unread for the current user. Only modifies records where the read status actually changes.
{
"specversion": "1.0",
"type": "User.Notification.Read",
"source": "MyApp v1.0",
"data": "{\"entryNos\":[5,8,12]}"
}
| Parameter | Type | Required | Description |
|---|---|---|---|
entryNos | Integer[] | Yes | Array of notification entry numbers to mark |
isRead | Boolean | No | Target read status. Default: true |
{
"entryNos": [5],
"isRead": false
}
| Field | Type | Description |
|---|---|---|
status | String | "Success" or "Error" |
noOfRecords | Integer | Number of records that were actually modified |
result | Array | Array of modified notification objects (see Common Structure) |
{
"status": "Success",
"noOfRecords": 2,
"result": [
{
"entryNo": 5,
"threadId": "00000000-0000-0000-0000-000000000000",
"parentEntryNo": 0,
"recipientUserId": "ADMIN",
"senderUserId": "SYSTEM",
"relatedTableId": 0,
"relatedRecordSystemId": "00000000-0000-0000-0000-000000000000",
"approvalEntryNo": 0,
"subject": "Approval required",
"body": "Purchase order PO-2001 requires your approval.",
"isRead": true,
"sourceEntrySystemId": "00000000-0000-0000-0000-000000000000",
"systemId": "b2c3d4e5-f6a7-8901-bcde-f23456789012",
"systemCreatedAt": "2024-01-15T09:00:00Z",
"systemModifiedAt": "2024-01-15T11:45:00Z",
"notificationType": "Approval"
}
]
}
{
"status": "Error",
"error": "Missing required field 'entryNos' (array of integers) in request."
}
isRead is omitted, defaults to true (mark as read)Direction: Inbound (Write operation)
Purpose: Sends a new notification to a specified user. The sender is automatically set to the current user (caller identity). Supports threading via threadId and parentEntryNo.
{
"specversion": "1.0",
"type": "User.Notification.Send",
"source": "MyApp v1.0",
"data": "{\"recipientUserId\":\"JOHN\",\"subject\":\"Task completed\",\"body\":\"The report has been generated.\"}"
}
| Parameter | Type | Required | Description |
|---|---|---|---|
recipientUserId | Text | Yes | User ID of the recipient |
subject | Text | Yes | Notification subject line |
body | Text | No | Notification body text |
threadId | GUID | No | Thread identifier to group related notifications |
parentEntryNo | Integer | No | Parent notification entry number. Required if threadId is set |
relatedTableId | Integer | No | Table ID of the related BC record |
relatedRecordSystemId | GUID | No | SystemId of the related BC record |
notificationType | Text | No | Notification type enum name (e.g., "Approval") |
{
"recipientUserId": "JOHN",
"subject": "Approval required",
"body": "PO-2001 needs your approval.",
"threadId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"parentEntryNo": 10,
"relatedTableId": 38,
"relatedRecordSystemId": "c4d5e6f7-a8b9-0123-cdef-456789012345",
"notificationType": "Approval"
}
Returns the created notification record:
| Field | Type | Description |
|---|---|---|
status | String | "Success" or "Error" |
noOfRecords | Integer | Always 1 on success |
result | Array | Array containing the created notification object (see Common Structure) |
{
"status": "Success",
"noOfRecords": 1,
"result": [
{
"entryNo": 15,
"threadId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"parentEntryNo": 10,
"recipientUserId": "JOHN",
"senderUserId": "ADMIN",
"relatedTableId": 38,
"relatedRecordSystemId": "c4d5e6f7-a8b9-0123-cdef-456789012345",
"approvalEntryNo": 0,
"subject": "Purchase order PO-2001 requires approval",
"body": "Please review and approve purchase order PO-2001 for vendor 10000.",
"isRead": false,
"sourceEntrySystemId": "00000000-0000-0000-0000-000000000000",
"systemId": "d5e6f7a8-b9c0-1234-def0-567890123456",
"systemCreatedAt": "2024-01-15T14:30:00Z",
"systemModifiedAt": "2024-01-15T14:30:00Z",
"notificationType": "Approval"
}
]
}
{
"status": "Error",
"error": "Missing required field 'recipientUserId' in request."
}
{
"status": "Error",
"error": "Missing required field 'parentEntryNo' when 'threadId' is specified."
}
threadId is provided, parentEntryNo is requiredisRead = falsenotificationType maps to the Notification Entry Type enum; unrecognized values are ignoredDirection: Outbound (Read operation)
Purpose: Retrieves all notifications belonging to a specific thread. The current user must be a recipient of at least one notification in the thread.
{
"specversion": "1.0",
"type": "User.Notification.Thread",
"source": "NotificationUI v3.0",
"subject": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
| Parameter | Type | Required | Description |
|---|---|---|---|
subject | GUID | Yes | Thread ID as a GUID string |
skip | Integer | No | Number of records to skip. Default: 0. |
take | Integer | No | Maximum records to return. Default: all. |
{
"specversion": "1.0",
"type": "User.Notification.Thread",
"source": "NotificationUI v3.0",
"subject": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"data": "{\"skip\":0,\"take\":10}"
}
| Field | Type | Description |
|---|---|---|
status | String | "Success" or "Error" |
noOfRecords | Integer | Total records in the thread |
result | Array | Array of notification objects (see Common Structure) |
{
"status": "Success",
"noOfRecords": 2,
"result": [
{
"entryNo": 10,
"threadId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"parentEntryNo": 0,
"recipientUserId": "JOHN",
"senderUserId": "ADMIN",
"relatedTableId": 38,
"relatedRecordSystemId": "c4d5e6f7-a8b9-0123-cdef-456789012345",
"approvalEntryNo": 0,
"subject": "Purchase order PO-2001 requires approval",
"body": "Please review and approve.",
"isRead": true,
"sourceEntrySystemId": "00000000-0000-0000-0000-000000000000",
"systemId": "d5e6f7a8-b9c0-1234-def0-567890123456",
"systemCreatedAt": "2024-01-15T09:00:00Z",
"systemModifiedAt": "2024-01-15T10:00:00Z",
"notificationType": "Approval"
},
{
"entryNo": 12,
"threadId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"parentEntryNo": 10,
"recipientUserId": "ADMIN",
"senderUserId": "JOHN",
"relatedTableId": 38,
"relatedRecordSystemId": "c4d5e6f7-a8b9-0123-cdef-456789012345",
"approvalEntryNo": 0,
"subject": "Re: Purchase order PO-2001",
"body": "Approved. Looks good.",
"isRead": false,
"sourceEntrySystemId": "00000000-0000-0000-0000-000000000000",
"systemId": "e6f7a8b9-c0d1-2345-ef01-678901234567",
"systemCreatedAt": "2024-01-15T10:15:00Z",
"systemModifiedAt": "2024-01-15T10:15:00Z",
"notificationType": "Approval"
}
]
}
{
"status": "Error",
"error": "The subject must contain the Thread ID (GUID) to retrieve."
}
{
"status": "Error",
"error": "No notifications found for the specified Thread ID and current user."
}
Direction: Inbound (Write operation)
Purpose: Creates an email draft in Business Central outbox without sending it. Supports HTML body and URL-based attachments.
{
"specversion": "1.0",
"type": "Email.Draft.Set",
"source": "MyApp v1.0",
"data": "{\"to\":[\"buyer@contoso.com\"],\"subject\":\"PO 1005\",\"htmlBody\":\"<p>Please review.</p>\",\"relatedTableId\":38,\"attachments\":[{\"fileName\":\"spec.pdf\",\"contentType\":\"application/pdf\",\"url\":\"https://example.com/spec.pdf\"}]}"
}
| Parameter | Type | Required | Description |
|---|---|---|---|
to | Text or Text[] | Yes | Recipient email address(es). Supports ;/, delimited string or array. |
subject | Text | Yes | Email subject line. |
htmlBody | Text | No | HTML body content. |
body | Text | No | Fallback body when htmlBody is omitted. |
cc | Text or Text[] | No | CC recipient email address(es). |
bcc | Text or Text[] | No | BCC recipient email address(es). |
emailScenario | Text | No | Explicit Email Scenario enum name. |
relatedTableId | Integer | No | Used for best-guess scenario selection when emailScenario is omitted. |
attachments | Object[] | No | URL-based attachments. Each object requires fileName + (url or contentUrl). |
| Field | Type | Description |
|---|---|---|
status | String | "Success" or "Error" |
messageId | GUID | Draft email message ID |
outboxSystemId | GUID | SystemId of created Email Outbox entry |
outboxUrl | String | Web client URL to open the created outbox draft/card context |
emailScenarioResolved | String | Resolved Email Scenario name from request/context |
{
"status": "Success",
"messageId": "d8f0f4d7-2f8b-4a4c-90e2-9f5c2d9d0f42",
"outboxSystemId": "26d55e6d-8b76-4d96-9f8c-2fb0fcf7e6a5",
"outboxUrl": "https://businesscentral...",
"emailScenarioResolved": "Purchasing"
}
Resolution order:
emailScenario from requestrelatedTableIdDefaultEmail ScenarioFor asynchronous processing (Queue API), subscribe to External Business Events:
Webhook payload: { MessageId, MessageType: "User.Notification.*", ResponseContentLink, Timestamp }
Use ResponseContentLink to directly download the response, or use MessageId to fetch via Data API. See Events_and_Webhooks.md for setup.
© Origo – Cloud Events Base Extension