Pages Menu

Posted by on Jul 17, 2017 in Microsoft Teams

How to Manage Microsoft Teams & Send Messages using the Teams API in Microsoft Graph

How to Manage Microsoft Teams & Send Messages using the Teams API in Microsoft Graph

Little known Microsoft Teams fact #345: there’s an API for managing teams and channels, and sending messages! It’s in beta and there’s some gaps in functionality, but that doesn’t stop us from having a play with it!

Microsoft Graph & Graph Explorer

Microsoft Graph is Microsoft’s one-stop shop for API access to an Office365 instance. Whether it’s mail, contacts, calendar, documents, devices or something else, you can use Graph to access data programmatically in a standard, REST-ful way using HTTP requests. Because all the access is done from a single place, there’s only one authentication process to worry about.

Because all API access is being funneled into Graph it means that Microsft can concentrate on making the Graph API experience excellent. One of the stand-out tools they have to do this is the Graph Explorer. This interactive web application lets you explore the Graph API using either a demo tenant or your own data, see all the available calls and what data is returned. It’s great for exploring the API before starting to write code, and the full request and response traces are shown, so when you’re ready to program you know what to expect.

I’ll be using the Graph Explorer in this blog post to show you the API calls I’m making, but there’s a short section at the end on how to take these calls and use them in your application.

You can access the Graph Explorer and play along by going to

The first thing I did was to sign in with my own credentials in the top left-hand corner: you don’t have to do this, but it’s more fun as you can see your own data this way.

There are two gotchas you should know about. Firstly, when you authenticate to Graph Explorer it will request a basic set of access rights. If you try and access data which isn’t covered by those rights then you’ll receive a Access Denied style error message. However the Explorer will notice this and will prompt you to select a different set of access rights. Each call is well documented with the permissions rights which are required so it’s easy to see what you need. After changing permission set you’ll need to log in again, at which point you should then be able to make the call with the correct rights.

The second thing to be aware of is that by default the Graph Explorer defaults to only showing you calls which are fully and generally available. Some of the API calls (including the Teams ones) are still in Beta so you have to explicity “opt in” to those to see them in the Explorer. To do this, select the version drop down in-between the Verb and URI fields, which in the screenshot above says “v1.0” and choose “beta”. This will update the IntelliSense of the fields as well so you’ll still get auto-complete for the beta calls.

Listing Teams I’m a member of

Let’s get started. I’m going to showcase a number of the different API calls for Teams, so you can see what they do. Firstly, let’s get a list of teams I’m a member of:


As you can see from the screenshot, there’s a dedicated call to get teams. This is good because, under the hood, Teams are represented as Groups, so listing and creating can quickly get quite complicated. It’s good to have a single call to be able to quickly get back Teams. You need the ID of the team for any further calls you make to do with that Team.

Getting Information About a Team

Now that we have the ID of a team we can get all details about it. Remember that a Team is represented and stored as a special type of Group, so you get information about it by specifying a Group with the ID:


This gives you some useful information, such as the email address for the Team, whether it’s Private or Public, when it was created etc. Here’s a sample response in full:


    "@odata.context": "$metadata#groups/$entity",
    "id": "d2b6c7fe-f440-446b-99d8-9ac12e036bf0",
    "deletedDateTime": null,
    "classification": null,
    "createdDateTime": "2017-03-15T05:42:16Z",
    "description": "An open forum for the Manufacturing team to communicate with the company at large.",
    "displayName": "Manufacturing Management",
    "groupTypes": [
    "mail": "[email protected]",
    "mailEnabled": true,
    "mailNickname": "manufacturingmanagement",
    "membershipRule": null,
    "membershipRuleProcessingState": null,
    "onPremisesLastSyncDateTime": null,
    "onPremisesProvisioningErrors": [],
    "onPremisesSecurityIdentifier": null,
    "onPremisesSyncEnabled": null,
    "preferredLanguage": null,
    "proxyAddresses": [
        "SMTP:[email protected]"
    "renewedDateTime": "2017-03-15T05:42:16Z",
    "resourceBehaviorOptions": [],
    "resourceProvisioningOptions": [],
    "securityEnabled": true,
    "theme": null,
    "visibility": "Public"

List Channels in a Team

A Team can contain multiple Channels – which we can also list out with its own URL to describe the Channels in a Group (Team):


From the screenshot you can see that there is only one Channel in this Team – the General channel.

Adding a New Channel to a Team

Let’s programmatically create a new channel! We can do this by changing the Verb dropdown from GET to POST and sending a POST command to the same /channels URL as above:


In the Request Body we provide a JSON representation of the new channel, with the displayName and description:


  "displayName": "World Domination Plans",
  "description": "This channel is where we plot our evil plans"

If the request is successful the response contains the ID of the newly created Team.

Just to prove it, if we now make the GET request again to show the channels in this Team, we can see the newly created Channel:

The new channel also shows in the Teams client:

Adding a message to a Teams Channel

With the Beta API today we can create new messages in a Teams Channel, but we can’t read messages or send direct to users. Both these features are expected to be added to the API feature list soon.

To send a message to a channel we need to know the ID of the channel (and of the group). There’s a specific POST message which is made to create a new “chat thread”, including a Request Body with the message:


The Request Body includes the actual message.

 "requestMessage": {
    "body": {
       "contentType": 1,
       "content": "Hello from Graph!"

The contentType is 0 for plain text, or 1 for HTML. This feels a little bit fragile for now so expect this to change in a future release.

And, here’s that message in the Teams client:

Exploration Complete, Now What?

Once you’ve had a chance to look through the Graph Explorer and decided what calls you want to make in order to get the data you need, you’ll find that Microsoft have put a lot of effort into making consuming the Graph API as simple as possible.

There are SDKs and code samples for a wide variety of different programming languages, including .NET but also Ruby, Python, iOS etc. Start by going to to get started. Fundamentally though, you’re just making and receiving HTTP calls – so it’s very easily consumed in practically any language and on any device.

What’s Next?

There is currently an open UserVoice thread of the issue of a Developer API for Teams, so it looks like we can look forward to more functionality being added to what’s already available. However, there’s plenty of exciting use cases made possible with these API calls today – so let me know in the comments what you’re using these for!



Written by Tom Morgan

Tom is a Microsoft Teams Platform developer and Microsoft MVP who has been blogging for over a decade. Find out more.
Buy the book: Building and Developing Apps & Bots for Microsoft Teams. Now available to purchase online with free updates.


  1. I am looking for a functionality, to fetch the presence of a particular user/group of user from the Skype for business using this API .

  2. As an admin with scope Group.Read.All, is there a way to do this for teams I am not a member of?

    I’m getting stuck on getting the channels of a team – getting 403 “Access Denied”, but I thought with my permissions I’d be able to see this!

Post a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.