# Notification Tray

{% hint style="info" %}
Notification Tray is currently in Private Beta. Please submit your request to the[**social.plus Help Center**](https://socialplus.atlassian.net/servicedesk/customer/portals) to enable this feature. It will take approximately 5 business days to process your request.
{% endhint %}

The notification tray service is designed to automatically create and group notification records in a notification tray separated by user. The main function of this service is to provide the notification history for each user.

Here's an example of a simple notification tray that we have customized with this service. As shown in the picture, the Notification Tray contains a history of notifications displayed as rows of notification records. Each notification record contains details about a particular notification, including a list of the actors who acted, the action performed (verb), and the target of the action (target).

<figure><img src="https://2352509137-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MX0mOAVWkotGme0iRzu%2Fuploads%2FrTL3ik3SjYgGhsUROpz2%2Fimage.png?alt=media&#x26;token=703303e4-7269-4f00-81b7-b4d66865eabb" alt="" width="346"><figcaption></figcaption></figure>

## Concept <a href="#specification" id="specification"></a>

* A notification record consists of actors, a verb, and a target - for example:
  * John Doe and 3 others commented on Sarah Janes's Post
    * **Actors:** John Doe and 3 other users
    * **Verb:** comment
    * **Target:** Sarah Jane's Post
* Notification Tray automatically groups events with the same verb and target together and aggregates a list of actors into the same Notification Record.
* By default, the notification tray displays up to 10 notification records per page, sorted from newest to oldest, using the date of the last update as a reference. All notification records are stored for 90 days from the last update.
* Each notification record displays up to 3 actor names, sorted by the date of record activity, except for mentions. They won't be grouped but shown individually.
* ImageUrl of a notification record is the profile image of the latest actor who acts on the target.
* The notification record expires 90 days after the timestamp of the `lastUpdate` and is then deleted from Notification Tray after expiring.
* When a user leaves a community, the user's notification records are not updated with the target associated with the community. When the user rejoins a community, the notification records are updated again, but events that happened during the time the user left the community are not retroactively reflected in the record.

### Scenarios

The following table shows supported scenarios and Tray Message that is recorded in the Notification Record.

<table><thead><tr><th>Target Type</th><th>Verb</th><th width="121">Scenario</th><th width="247">Tray Message</th><th>Notification Target</th></tr></thead><tbody><tr><td>Post</td><td>post</td><td>A create post on community</td><td><code>{DisplayName A}</code> posted in <code>{CommunityName}</code></td><td>Community's members</td></tr><tr><td></td><td></td><td>A,B create post on community</td><td><code>{DisplayName B}</code> and <code>{DisplayName A}</code> created post in <code>{CommunityName}</code></td><td>Community's members</td></tr><tr><td></td><td></td><td>A,B,C,D create post on community</td><td><code>{DisplayName D}</code>, <code>{DisplayName C}</code> and <code>{2}</code> others posted in {CommunityName}</td><td>Community's members</td></tr><tr><td>Comment</td><td>comment</td><td>B comment on A’s post</td><td>User Feed: <code>{DisplayName B}</code> commented on your post<br>Community Feed:<br><code>{DisplayName B}</code> commented on your post in <code>{CommunityName}</code></td><td>Post owner (User A)</td></tr><tr><td></td><td></td><td>B,C comment on A’s post</td><td><p>User Feed:</p><p><code>{DisplayName C}</code> and <code>{DisplayName B}</code>commented on your post<br>Community Feed:</p><p><code>{DisplayName C}</code> and <code>{DisplayName B}</code> commented on your post in <code>{CommunityName}</code></p></td><td>Post owner (User A)</td></tr><tr><td></td><td></td><td>B,C,D,E comment on A’s post</td><td>User Feed:<br><code>{DisplayName E}</code>, <code>{DisplayName D}</code> and <code>{2}</code>others commented on your post<br>Community Feed:<br><code>{DisplayName E}</code>, <code>{DisplayName D}</code> and <code>{2}</code> others commented on your post in <code>{CommunityName}</code></td><td>Post owner (User A)</td></tr><tr><td>Reply</td><td>mentreply</td><td>B reply on A’s comment</td><td>User Feed: <code>{DisplayName B}</code> has replied to your comment.<br>Community Feed:<br><code>{DisplayName B}</code> has replied to your comment.</td><td>Comment owner (User A)</td></tr><tr><td></td><td></td><td>B, C reply on A’s comment</td><td><p>User Feed:</p><p><code>{DisplayName C}</code> and <code>{DisplayName B}</code> have replied to your comment.<br>Community Feed:</p><p><code>{DisplayName C}</code> and<br><code>{DisplayName B}</code> have replied to your comment.</p></td><td>Comment owner (User A)</td></tr><tr><td></td><td></td><td>B, C, D, E reply on A’s comment</td><td><p>User Feed:</p><p><code>{DisplayName E}</code>, <code>{DisplayName D}</code> and 2 others have replied to your comment.<br>Community Feed:</p><p><code>{DisplayName E}</code>, <code>{DisplayName D}</code> and 2 others have replied to your comment.</p></td><td>Comment owner (User A)</td></tr><tr><td>Reaction</td><td>reaction/mentreact</td><td>B react on A’s post/comment</td><td>User Feed: <code>{DisplayName B}</code> added a reaction to your post/comment<br>Community Feed: <code>{DisplayName B}</code> added a reaction to your post/comment in <code>{CommunityName}</code></td><td>Post/Comment owner (User A)</td></tr><tr><td></td><td></td><td>B,C react on A’s post/comment</td><td>User Feed: <code>{DisplayName C}</code> and <code>{DisplayName B}</code> added reactions to your post/comment<br>Community Feed: <code>{DisplayName C}</code> and <code>{DisplayName B}</code> added reactions to your post/comment in <code>{CommunityName}</code></td><td>Post/Comment owner (User A)</td></tr><tr><td></td><td></td><td>B,C,D,E react on A’s post/comment</td><td>User Feed: <code>{DisplayName E}</code>, <code>{DisplayName D}</code> and <code>{2}</code> others added reactions to your post/comment<br>Community Feed:<code>{DisplayName E}</code>, <code>{DisplayName D}</code> and <code>{2}</code> others added reactions to your post/comment in <code>{CommunityName}</code></td><td>Post/Comment owner (User A)</td></tr><tr><td><a data-footnote-ref href="#user-content-fn-1"><mark style="color:red;">*</mark></a>Mention</td><td>mention</td><td>A mentioned B on A post/comment in a community</td><td><code>{DisplayName A}</code> has mentioned you on a post/comment in <code>{CommunityName}</code></td><td>User B</td></tr><tr><td></td><td></td><td>A mentioned B on A post/comment in a user feed</td><td><code>{DisplayName A}</code> has mentioned you on a post/comment in <code>{DisplayName A}</code> feed</td><td>User B</td></tr></tbody></table>

### Last Read & Has Read

The notification tray supports 2 reading levels as follows:

1. **Last Read**: Update the last read timestamp of the user. This is used to update the total unread count of notification records.
2. **Has Read**: Flag on each notification record that shows whether the user has explicitly read or click the notification record. This is represented as `hasRead` value inside each notification record JSON and can be used to display 'unread dot' on each notification record on Notification Tray.

## GET /notifications/v3

> Get the total unread count of notifications in the user's notification tray.

```json
{"openapi":"3.0.1","info":{"title":"Notification Tray API","version":"1"},"servers":[{"url":"https://beta.amity.services"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"NotificationTotalUnread":{"type":"object","properties":{"data":{"type":"object","properties":{"totalUnreadCount":{"type":"number","description":"Number of total unread notification tray record of the user."}}}}}}},"paths":{"/notifications/v3":{"get":{"summary":"Get the total unread count of notifications in the user's notification tray.","responses":{"200":{"description":"Notification Total Unread Count","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationTotalUnread"}}}}}}}}}
```

## GET /notifications/v3/mark-all-as-read

> Mark all the records as read.

```json
{"openapi":"3.0.1","info":{"title":"Notification Tray API","version":"1"},"servers":[{"url":"https://beta.amity.services"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"NotificationMarkAllAsRead":{"type":"object","properties":{"data":{"type":"object","properties":{"message":{"type":"string","description":"Status of process."}}}}}}},"paths":{"/notifications/v3/mark-all-as-read":{"get":{"summary":"Mark all the records as read.","responses":{"200":{"description":"Marked all the records as read","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationMarkAllAsRead"}}}}}}}}}
```

## GET /notifications/v3/history

> Retrieve notification records of a user

```json
{"openapi":"3.0.1","info":{"title":"Notification Tray API","version":"1"},"servers":[{"url":"https://beta.amity.services"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"NotificationHistory":{"type":"object","properties":{"totalPages":{"type":"integer","description":"Show how many pages user have."},"nextPage":{"type":"integer","description":"Show the next page timestamp."},"data":{"type":"array","items":{"$ref":"#/components/schemas/NotificationRecord"}}}},"NotificationRecord":{"type":"object","properties":{"v_tarid_uid":{"type":"string","description":"Primarykey of the record."},"description":{"type":"string","description":"Tray Message of the record."},"verb":{"$ref":"#/components/schemas/NotificationVerb"},"imageUrl":{"type":"string","description":"Avatar image of the record"},"avatarCustomUrl":{"type":"string","description":"Avatar image of the record (if last actor use avatarCustomUrl)."},"targetType":{"type":"string","description":"Type of the target","enum":["community","post"]},"targetName":{"type":"string","description":"Name of the target"},"hasRead":{"type":"boolean","description":"Flag indicating whether the user has read the record"},"lastUpdate":{"type":"integer","description":"Timestamp of when the record is last updated"},"actors":{"type":"object","description":"Latest actors (up to 3 actors) who performed the verb on the target.","properties":{"name":{"type":"string","description":"Name of the user"}}},"actorsCount":{"type":"integer","description":"Total count of the actors"},"parentTargetId":{"type":"string","description":"The targetId of Parent incase this record verb = reaction, mentreply, comment."},"targetId":{"type":"string","description":"The targetId of this record."},"lastActionId":{"type":"string","description":"The ID of the last action, which could be postId, commentId, or reactionID, depends on the verb."},"lastActionSegmentNo":{"type":"number","description":"The index of the last action (supported only for comments)."}}},"NotificationVerb":{"type":"string","enum":["post","comment","reaction","mentreply"]}}},"paths":{"/notifications/v3/history":{"get":{"summary":"Retrieve notification records of a user","parameters":[{"name":"startAfter","in":"query","description":"timeStamp of last record of previous page.","required":false,"schema":{"type":"integer","default":1}}],"responses":{"200":{"description":"Notification history JSON","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationHistory"}}}}}}}}}
```

## POST /notifications/v2/last-read

> Update lastRead timestamp of the user

```json
{"openapi":"3.0.1","info":{"title":"Notification Tray API","version":"1"},"servers":[{"url":"https://beta.amity.services"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"NotificationHasRead":{"type":"object","properties":{"data":{"type":"string","description":"Request has succeeded."}}}}},"paths":{"/notifications/v2/last-read":{"post":{"summary":"Update lastRead timestamp of the user","responses":{"200":{"description":"Request has succeeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationHasRead"}}}}}}}}}
```

## POST /notifications/v2/read

> Mark a notification record as read

```json
{"openapi":"3.0.1","info":{"title":"Notification Tray API","version":"1"},"servers":[{"url":"https://beta.amity.services"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"NotificationVerb":{"type":"string","enum":["post","comment","reaction","mentreply"]},"NotificationHasRead":{"type":"object","properties":{"data":{"type":"string","description":"Request has succeeded."}}}}},"paths":{"/notifications/v2/read":{"post":{"summary":"Mark a notification record as read","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"verb":{"$ref":"#/components/schemas/NotificationVerb"},"targetId":{"type":"string"}}}}}},"responses":{"200":{"description":"Request has succeeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationHasRead"}}}}}}}}}
```

## DELETE /notifications/v3/delete-all

> Delete all notification of the user

```json
{"openapi":"3.0.1","info":{"title":"Notification Tray API","version":"1"},"servers":[{"url":"https://beta.amity.services"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"NotificationDeleteAll":{"type":"object","properties":{"data":{"type":"string","description":"Success."}}}}},"paths":{"/notifications/v3/delete-all":{"delete":{"summary":"Delete all notification of the user","responses":{"200":{"description":"Request has succeeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationDeleteAll"}}}}}}}}}
```

## Limitations

* When a user **changes** their display name, the actor's name in Tray Message is not updated.
* **Notification** **Tray** currently **does not support**
  * **Post** on user feed
  * **Grouping** **mention** into one record
* **Customization** of **`description`** is not supported. If customization/localization of notification records is needed we recommend constructing the message at the frontend as notification records already contain all the information needed.

{% hint style="danger" %}

#### Are you still on version 2?

{% endhint %}

Don't worry, Version 2 can still be used, but it won't support the mention feature. So, we highly recommend migrating to v3, and here is the list of changes needed to use Version 3!

<table><thead><tr><th width="185">Breaking Change</th><th width="250.33333333333331">Version 2</th><th>Version 3</th></tr></thead><tbody><tr><td>Pagination</td><td>?page=1</td><td>?startAfter=1692248943383</td></tr><tr><td>Response data</td><td><pre class="language-json"><code class="lang-json">{
    "totalPages": 2,
    "data": [
    .
    .
    .
    ]
}
</code></pre></td><td><pre><code>{
    "totalPages": 2,
    "data": [
    .
    .
    .
    ],
    "nextPage": 1692248943383
}
</code></pre></td></tr></tbody></table>

[^1]: Currently supported on version 3++
