February 28th, 2020

Announcing change notifications for Microsoft Teams messages

Nick Kramer (TEAMS)
Principal Product Manager

One of the most common requests we receive in UserVoice is change notifications for messages.  Developers want to build apps that can listen to Microsoft Teams messages in near-real time, without polling, to enable scenarios such as bots that listen to messages on which they aren’t @mentioned, or assist with enterprise information archiving and data loss prevention.  We are pleased to announce that developers can now subscribe to change notifications for Microsoft Teams messages. This feature is available in beta on the Microsoft Graph API.

Using the Microsoft Graph POST /subscriptions API, developers can subscribe to messages in a particular channel (/teams/{id}/channels/{id}/messages) or in a particular 1:1 or group chat thread (/chats/{id}/messages). You can hear about new messages, replies, edits, reactions, and deletes.

Developers can also subscribe to all messages in a tenant. This requires the creation of two subscriptions: one for the /teams/allMessages resource and one for /chats/allMessages. Note that during the preview, you may use this API without fees, subject to the Microsoft APIs Terms of Use. However, users of apps that use the API might be required to have subscriptions to specific Microsoft 365 offerings. Upon general availability, Microsoft may require you or your customers to pay additional fees based on the amount of data accessed through the API.

As with all Microsoft Graph webhooks, creating a subscription starts with passing in the URL of the webhook you wish Graph to call back to, and validating the subscription creation within your web service. When a new message arrives, Graph will send that message to your webhook. Teams messages are the first Graph resource to support webhooks with resource data, so you don’t need to make a second API call to retrieve the message text.

Example — Setting up a Teams message subscription 

POST https://graph.microsoft.com/beta/subscriptions  
{ 
  "resource": "teams/97edf8ce-b0f5-4bc8-91e8-7c73185f18c0/channels/19:945129d1eede4536a6a9811e71d7b2a6@thread.skype/messages", 
  "notificationUrl": "https://apps.contoso.com/messageswebhookhandler", 
  "changeType": "created,updated,deleted", 
  "clientState": "6b5acd8b-98d1-48be-a8be-e12842fadcd5", 
  "expirationDateTime": "2020-02-13T01:33:09.1416264Z", 
  "encryptionCertificate": "MIIDNDCCAhygAwIBAgIQLR3AKZYNS42E....", 
  "encryptionCertificateId": "70ffad80b880496a968e83091174a979", 
  "includeProperties": "True" 
} 

After you request the subscription, Microsoft Graph will ping your URL to confirm that it wants notifications. As subsequent messages are updated, you will see requests to your web services that look as follows: 

POST https://apps.contoso.com/messageswebhookhandler 
{
  "value": [
    {
      "encryptedContent": {
        "data": "zotuEncwI9pBgKeFMcUlxBs3u+I6pvH54skorpmLQjf8pi2....", 
        "dataSignature": "E/GsVEUAzZGbunSNlx8IPBKjgab/lqga2/A+iO/vMME=",
        "dataKey": "lXMs2rLdpx/uCB4iZv2ahU23X/...", 
        "encryptionCertificateId": "70ffad80b880496a968e83091174a979", 
        "encryptionCertificateThumbprint": "84DAB632CC42024DD80441A1B0C307B953BD5A2E" 
      },
      "subscriptionId": "da94613a-d11a-41e2-b635-295a59b29f3b",
      "changeType": "created",
      "tenantId": "139d16b4-7223-43ad-b9a8-674ba63c7924",
      "clientState": "ClientSecret",
      "subscriptionExpirationDateTime": "2020-02-13T01:33:09.1416264+00:00",
      "resource": "teams('9403afc6-f959-413d-ba83-873ace7b51c7')/channels('19:fbc4cd1ea9ff4cd89cf1d734cf9e3c87@thread.skype')/messages('1581553690121')/replies('1581554024315')",
      "resourceData": {
        "id": "1581554024315",
        "@odata.type": "#Microsoft.Graph.ChatMessage",
        "@odata.id": "teams('9403afc6-f959-4312-ba83-873ace7b51c7')/channels('19:fbc4cd1ea9ff4cd89cf1d734cf9e3c87@thread.skype')/messages('1581553690121')/replies('1581554024315')"
      }
    }
  ],
  "validationTokens": [
    "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6I....."
  ]
}

Decrypting the encryptedContent gives the full message details:

{
  "body": {
    "contentType": "text",
    "content": "Hello world!"
  },
  "id": "1581554024315",
  "replyToId": "1581553690121",
  "etag": "1581554024315",
  "messageType": "message",
  "createdDateTime": "2020-02-13T00:33:44Z",
  "lastModifiedDateTime": null,
  "deletedDateTime": null,
  "subject": null,
  "summary": null,
  "importance": "normal",
  "locale": "en-us",
  "webUrl": "https://teams.microsoft.com/l/message/19%3Afbc4cd1ea9ff4cd89cf1d734cf9e3c87%40thread.skype/1581554024315?groupId=9403afc6-f959-4312-ba83-873ace7b51c7&tenantId=139d16b4-7223-43ad-b9a8-674ba63c7924&createdTime=1581554024000&parentMessageId=1581553690121",
  "from": {
    "application": null,
    "device": null,
    "user": {
      "id": "7ed20f7a-09c6-4a47-8ebf-a6a1f2588624",
      "displayName": "Megan Bowen",
      "userIdentityType": "aadUser"
    },
    "conversation": null
  },
  "attachments": [],
  "mentions": [],
  "policyViolation": null,
  "reactions": [],
  "replies": [],
  "hostedContents": []
}

Next steps 

You can get started by trying out the sample app.  See the documentation for more information about Microsoft Teams messaging webhooks. 

If you have any feedback about or suggestions for these APIs, please let us know via User Voice (under Teamwork). 

Happy hacking! 

 

Author

Nick Kramer (TEAMS)
Principal Product Manager