Introduction

This is a quick introduction to the Microsoft To Do API, focussing on the deprecated (but still actively used by Microsoft) Outlook API.

Microsoft Graph

Some time ago, Microsoft introduced Microsoft Graph, which aims to give access to basically all of the data from the Microsoft 365 cloud services.

As part of Microsoft Graph, there is the Microsoft To Do API which offers many operations one would expect from an API: listing tasks, creating tasks, updating tasks, deleting tasks.

However, there are some features, especially regarding the ordering of tasks and subtasks, that are currently not available in the Microsoft Graph API.

There is already a feature request in the Tech Community that can be upvoted to raise awareness of its importance to Microsoft.

The Microsoft Graph API has good documentation, so it should always be the preferred option, if possible. The remainder of this article is about older and undocumented APIs, for features that are not available in Microsoft Graph.

Outlook API

The API that is actually used by Microsoft itself (web app, desktop app and mobile app) is available under https://outlook.office.com/todob2/api/v1/. However, there seems to be no public documentation available. The best matching document is Outlook Task REST API reference (beta), but the URL paths there do not match the one that the Microsoft apps use.

The domain that is used by Microsoft apps is actually substrate.office.com. However, there is even less information available about that domain and from experiments, it seems that it is possible to simply use the API via the outlook.office.com domain.

Authentication

For authentication of the Outlook API, the same principles as for Microsoft Graph apply, so to be able to call the API, an App registration is required. For more information, see the authentication introduction.

For the Outlook API, app registration API permissions cannot be selected directly, but must be set by editing the app registration Manifest, which is a JSON document that describes the current app registration configuration.

The following entry, which adds the permission 6b49b74d-642f-4417-a6b4-820576845707 (Tasks.ReadWrite) for the resource 00000002-0000-0ff1-ce00-000000000000 (Office 365 Exchange Online, https://outlook.office.com/) needs to be added to the "requiredResourceAccess" array:

{
"resourceAppId": "00000002-0000-0ff1-ce00-000000000000",
"resourceAccess": [
{
"id": "6b49b74d-642f-4417-a6b4-820576845707",
"type": "Scope"
}
]
}

To follow the examples in the next sections, it is also required to enable the No keyboard (Device Code Flow) setting in the Azure portal under the Authentication page of the app registration.

The following examples use 12300000-0000-0000-0000-000000000321 as a placeholder value for the app registration’s Application ID. This needs to be replaced by the actual Application ID of the app registration you are using.

The first step is to request a device code:

curl -v https://login.microsoftonline.com/consumers/oauth2/v2.0/devicecode \
-d 'client_id=12300000-0000-0000-0000-000000000321&scope=https%3A//outlook.office.com/Tasks.ReadWrite'

This should return a JSON response of the following form:

{
"device_code": "FEDCBA[...]",
"message": "To sign in, use a web browser to open the page https://www.microsoft.com/link and enter the code ABCDE123 to authenticate."
}

After opening https://www.microsoft.com/link and entering the code, you will be prompted to allow your app registration to access your Microsoft account.

Finally, the following request can be executed to get a token. The correct Application ID (Client ID) and the device code from the previous response need to be used.

curl -v https://login.microsoftonline.com/consumers/oauth2/v2.0/token \
-d 'grant_type=urn:ietf:params:oauth:grant-type:device_code&client_id=12300000-0000-0000-0000-000000000321&device_code=FEDCBA[...]'

It should return a JSON response like this:

{
"token_type": "Bearer",
"scope": "https://outlook.office.com/Tasks.ReadWrite",
"access_token": "ABC[...]"
}

The field "scope" shows the correct scope for using the Outlook API and accessing task data. The field "access_token" contains the access token that needs to be passed to all following requests.

Data model

As mentioned in the beginning, a lot of the data is also available via Microsoft Graph API. However, there are some differences in the naming of the involved types.

In Microsoft Graph, the type at the top of the hierarchy is Task List. Each task list contains one or more Task objects and each task contains one or more Checklist Item objects.

In the Outlook API, the types are named Task Folder, Task and Subtask.

Getting data

To list task folders, use the following request.

curl -v https://outlook.office.com/todob2/api/v1/taskfolders \
-H "Authorization: Bearer ABC[...]"

This should return a JSON response, giving a list of task folders.

{
"DeltaLink": "https://outlook.office.com/todob2/api/v1/taskfolders?deltatoken=abc123&maxPageSize=50",
"Value": [
{
"Id": "AbCdEf==",
"Name": "Shopping",
"OrderDateTime": "2022-08-14T10:05:54Z",
[...]
},
[...]
]
}

The "DeltaLink" field contains a URL that can be queried to return the same list, but only including items that have been changed since the time the request was made.

The "OrderDateTime" is the field that controls the ordering of objects (task folders, tasks and subtasks). This data is currently not available in the Microsoft Graph API.

Even though the types have different names, they still reference the same objects. So the "Id" field from the Outlook API is an identifier that can be used to query the same object using the Microsoft Graph API.

To list all tasks in a task folder, use

curl -v https://outlook.office.com/todob2/api/v1/taskfolders/AbCdEf==/tasks \
-H "Authorization: Bearer ABC[...]"

and to list subtasks of a task, use

curl -v https://outlook.office.com/todob2/api/v1/tasks/AbCdEf==/subtasks/123 \
-H "Authorization: Bearer ABC[...]"

Modifying data

To modify the "OrderDateTime" field of a task folder, the following request could be used.

curl -v https://outlook.office.com/todob2/api/v1/taskfolders/AbCdEf== \
-H "Authorization: Bearer ABC[...]" \
-X PATCH \
-H "Content-Type: application/json" \
-d '{"OrderDateTime": "2023-04-09T07:00:00Z"}'

However, running this request will update the data, but will not inform connected clients (for example, mobile applications that are currently open) about the data change. To make sure the data update is pushed, we need to include the x-anchormailbox header.

When issuing requests, for example to list all task folders, the Outlook API will return a header x-target-resource-metadata with a value similar to CID:1234ABCD4321ABCD@87654321-4321-abcd-ef09-aaaaaaaaaaaa. The value for the x-anchormailbox header seems to be the part before the @ character.

When this header is included, the following request will also cause running apps to update immediately, showing the new data.

curl -v https://outlook.office.com/todob2/api/v1/taskfolders/AbCdEf== \
-H "Authorization: Bearer ABC[...]" \
-X PATCH \
-H "x-anchormailbox: CID:1234ABCD4321ABCD" \
-H "Content-Type: application/json" \
-d '{"OrderDateTime": "2023-04-09T07:00:00Z"}'

Final remarks

From looking at the network requests, we know that the Outlook API is actively being used by the Microsoft To Do apps. However, there is no exhaustive documentation for it. Because the API is not publicly documented, Microsoft is free to change it anytime. That means the steps in this article will probably stop working at some point.

To be safe, the Microsoft Graph API should be used whenever possible. It follows a publicly documented versioning scheme, so if things change, Microsoft will actively inform about it.

As Microsoft apps also need some API to be working correctly, I expect that the currently missing features will be available in Microsoft Graph API before the Outlook API is shut down.