Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
With Microsoft Graph, you can migrate users' existing message history and data from an external system into Teams. Users can continue their communications in a seamless manner and proceed without interruption by enabling the recreation of a third-party platform messaging hierarchy inside Teams.
Note
In the future, Microsoft might require you or your customers to pay extra fees based on the amount of data imported.
Permissions
| Scope name | Display name | Description | Type | Admin consent required | Entities/APIs covered |
|---|---|---|---|---|---|
| Teamwork.Migrate.All | Manage migration to Microsoft Teams | Creating and managing resources for migration to Teams. | Application-only | Yes | POST /team |
Note
Delegated authentication isn't supported.
Supported channel and chat types
Teams supports migrating external messages to the following channel and chat types:
New team and standard channel: Create a new team and its standard channels in migration mode to import content. This approach lets you import the exact structure of your external system into the new channel. To enable
migrationModefor a new standard team and channel, see Create a team and standard channel in migration mode.Existing channel or chat: Use any channel or chat that already exists in Teams, regardless of when you created it. This approach lets you add existing context to channels that are already active in Teams and maintains continuity for ongoing conversations. To enable migration mode in an existing channel or chat, see Existing channel migration.
Note
- Only standard channels are supported when creating a channel in migration mode from scratch.
- Federated content can't be imported. All imported content must come from the authenticated tenant and only one app can manage a thread at a time. Another app can import content only after the first app completes migration.
migrationMode is a special state that ensures data integrity by preventing the following operations during data migration.
- For new teams and standard channels:
- It restricts receipt of new messages
- It prevents adding or removing members
- For all supported channels and chat types:
- It allows importing historical messages with custom timestamps
- It maintains the original conversation structure and hierarchy
Content scope for import
The following table provides the content scope for existing channels and chats.
| In-scope | Out-of-scope |
|---|---|
| Team (general) | Announcements |
| Created time of the original message | Videos |
| Inline images as part of the message | Code snippets |
| Links to existing files in Microsoft 365 (Microsoft 365) SharePoint Online (SPO) or OneDrive (OD) | Stickers |
| Messages with rich text | Cross posts between channels |
| Message reply chain | Quotes |
| High throughput processing | |
| 1:1 and group chat messages | |
| Standard, private, and shared channel messages | |
| Up to 250 reactions | |
| @mentions and emojis |
Prerequisites
Analyze and prepare message data
- Review the third-party data to decide what to migrate.
- Extract the selected data from the third-party chat system.
- Map the third-party chat structure to the Teams structure.
- Convert import data into the format needed for migration.
Set up your Microsoft 365 tenant
- Ensure that a Microsoft 365 tenant exists for the import data. For more information on setting up a Microsoft 365 tenancy for Teams, see prepare your Microsoft 365 tenant.
- Make sure that team members are in Microsoft Entra ID. For more information, see add a new user to Microsoft Entra ID.
Import historical messages into Teams
You can import historical messages seamlessly into both existing and newly created channels or chats by performing the following steps:
- Start migration
- Check migration status
- Import messages
- Complete migration mode
- Verify migration mode completion
Step 1: Start migration
To start migrating a user's message history from any third-party platform to Teams, you can either create a new team and standard channel or use an existing channel or chat. Depending on your scenario, choose either of the following options:
Create a team and standard channel in migration mode
In this scenario, create a new team and standard channel in migrationMode to proceed with importing existing messages. migrationMode is supported only for standard channels.
Create a new team
- Create a new team with a back-in-time timestamp using the
createdDateTimeproperty. - Place the new team in
migrationModeby settingteamCreationModetomigration.
Note
The createdDateTime field is only populated for migrated teams or channels. If you update createdDateTime to a past timestamp, you can't move it to a future timestamp again.
migrationMode ensures that the original message timestamps are preserved, and prevents new messages from being sent when the migration is in progress.
Request (create a team in migration mode)
POST https://graph.microsoft.com/v1.0/teams
Content-Type:application/json
{
"@microsoft.graph.teamCreationMode":"migration",
"template@odata.bind":"https://graph.microsoft.com/v1.0/teamsTemplates('standard')",
"displayName":"My Sample Team",
"description":"My Sample Team’s Description",
"createdDateTime":"2020-03-14T11:22:17.043Z"
}
Response
HTTP/1.1 202 Accepted
Location: /teams/{team-id}/operations/{operation-id}
Content-Location: /teams/{team-id}
Error message
400 Bad Request
You can receive the error message in the following scenarios:
- If
createdDateTimeis set for future. - If
createdDateTimeis correctly specified, butteamCreationModeinstance attribute is missing or set to invalid value.
Create a new channel
- Create a new channel with a back-in-time timestamp using the
createdDateTimeproperty of the channel resource. - Place the new channel in migration mode by setting
channelCreationModetomigration.
Request (create a channel in migration mode)
POST https://graph.microsoft.com/v1.0/teams/{team-id}/channels
Content-Type: application/json
{
"@microsoft.graph.channelCreationMode":"migration",
"displayName":"Architecture Discussion",
"description":"This channel is where we debate all future architecture plans",
"membershipType":"standard",
"createdDateTime":"2020-03-14T11:22:17.047Z"
}
Response
HTTP/1.1 202 Accepted
{
"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#teams('team-id')/channels/$entity",
"id":"id-value",
"createdDateTime":null,
"displayName":"Architecture Discussion",
"description":"This channel is where we debate all future architecture plans",
"isFavoriteByDefault":null,
"email":null,
"webUrl":null,
"membershipType":null,
"moderationSettings":null
}
Error message
400 Bad Request
You can receive the error message in the following scenarios:
- If
createdDateTimeis set for future. - If
createdDateTimeis correctly specified butchannelCreationModeinstance attribute is missing or set to invalid value.
After you create a new team and standard channel, complete migration with the following steps:
Start migration on existing channels and chats
On existing channels or chats, use the startMigration API to enable channel migration mode or to enable chat migration mode
startMigration sets the migration state to InProgress and begins the message import process. For more information, see:
Existing channel migration
To enable migration mode on existing channels, use the startMigration API.
Request (existing channel in migration mode)
POST https://graph.microsoft.com/beta/teams/{team-id}/channels/{channel-id}/startMigration
{
"conversationCreationDateTime":"2024-01-01T00:00:00Z"
}
Tip
Microsoft Graph uses DateTimeOffset to represent date and time with a UTC offset for an accurate time zone.
The conversationCreationDateTime value must be greater than the minimum value for DateTimeOffset and less than the current value of the channel's createdDateTime.
Response
If the request is successful, the method returns an empty HTTP response.
HTTP/1.1 204 No Content
Example
POST https://graph.microsoft.com/beta/teams/57fb72d0-d811-46f4-8947-305e6072eaa5/channels/19:4b6bed8d24574f6a9e436813cb2617d8@thread.tacv2/startMigration
{
"conversationCreationDateTime":"2024-01-01T00:00:00Z"
}
Existing chat migration
To enable migration mode on existing chats, use the startMigration API.
Request (existing chat in migration mode)
POST https://graph.microsoft.com/beta/chats/{chat-id}/startMigration
{
"conversationCreationDateTime":"2024-01-01T00:00:00Z"
}
Tip
Microsoft Graph uses DateTimeOffset to represent date and time with a UTC offset for an accurate time zone.
The conversationCreationDateTime must be greater than the minimum value for DateTimeOffset and less than the current value of the chat's createdDateTime.
Response
If the request is successful, the method returns an empty HTTP response.
HTTP/1.1 204 No Content
Example
POST https://graph.microsoft.com/beta/teams/57fb72d0-d811-46f4-8947-305e6072eaa5/chats/19:4b6bed8d24574f6a9e436813cb2617d8@thread.tacv2/startMigration
{
"conversationCreationDateTime":"2024-01-01T00:00:00Z"
}
Consider the following important points:
- Define a minimum timestamp for messages to migrate. The provided timestamp must be older than the channel or chat's current
createdDateTime. This timestamp replaces the existingcreatedDateTimeof the channel. If you updatecreatedDateTimeto a past timestamp, you can't move it to a future timestamp again. - The
creationDateTimeproperty is optional in a request body. If omitted, thestartMigrationAPI uses the current date and time as the minimum timestamp. - The
startMigrationAPI starts the message migration process by setting the migration mode toInProgressfor a specified channel or chat.
Step 2: Check migration status
Call Get channel or Get chat to confirm that the migrationMode state is set to InProgress. For more information, see:
Step 3: Import messages
Now you can import back-in-time messages by including the createdDateTime and from keys in the request body.
Note
- The API doesn't support messages imported with a creation date and time earlier than the
createdDateTimefor the message thread. createdDateTimemust be unique across messages in the same thread.createdDateTimesupports timestamps with milliseconds precision. For example, if the incoming request message hascreatedDateTimeset to 2020-09-16T05:50:31.0025302Z, the API converts it to 2020-09-16T05:50:31.002Z when ingesting the message.
Request (POST message that is text-only)
POST https://graph.microsoft.com/v1.0/teams/team-id/channels/channel-id/messages
{
"createdDateTime":"2019-02-04T19:58:15.511Z",
"from":{
"user":{
"id":"id-value",
"displayName":"John Doe",
"userIdentityType":"aadUser"
}
},
"body":{
"contentType":"html",
"content":"Hello World"
}
}
Response
HTTP/1.1 200 OK
{
"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#teams('team-id')/channels('channel-id')/messages/$entity",
"id":"id-value",
"replyToId":null,
"etag":"id-value",
"messageType":"message",
"createdDateTime":"2019-02-04T19:58:15.58Z",
"lastModifiedDateTime":null,
"deleted":false,
"subject":null,
"summary":null,
"importance":"normal",
"locale":"en-us",
"policyViolation":null,
"from":{
"application":null,
"device":null,
"conversation":null,
"user":{
"id":"id-value",
"displayName":"Joh Doe",
"userIdentityType":"aadUser"
}
},
"body":{
"contentType":"html",
"content":"Hello World"
},
"attachments":[
],
"mentions":[
],
"reactions":[
]
}
Error message
You receive the following error message if you set the createdDateTime property to a future date and time.
400 Bad Request
Request (POST message with an inline image)
Note
- There are no special permission scopes in this scenario since the request is part of
chatMessage. - The scopes for
chatMessageapply here.
POST https://graph.microsoft.com/v1.0/teams/team-id/channels/channel-id/messages
{
"body": {
"contentType":"html",
"content": "<div><div>\n<div><span><img height=\"250\" src=\"../hostedContents/1/$value\" width=\"176.2295081967213\" style=\"vertical-align:bottom; width:176px; height:250px\"></span>\n\n</div>\n\n\n</div>\n</div>"
},
"hostedContents":[
{
"@microsoft.graph.temporaryId":"1",
"contentBytes": "iVBORw0KGgoAAAANSUhEUgAAANcAAAExCAYAAADvFzeeAAAXjklEQVR4Ae2d/XNU1RnH+9e0FFrA0RCIyaS8hRA0HV5KbS1gHRgVpjMClY4GHJ3yYm1HCmXaWttaaZUZtIIFKYi8lFAkvOQ9u5vN225IARVBbX9/Os9NbrLZbMjmhCfJPX5+2Lmb3T25y3O+n/M599x7w9f+++UXwoMakIF7n4GvUdR7X1RqSk01A8CFuZm5GGUAuIwKi72wF3ABF+YyygBwGRUWc2Eu4AIuzGWUAeAyKizmwlzABVyYyygDwGVUWMyFuYALuDCXUQaAy6iwmAtzARdwfWXMdeuzT+TGxz3Sfb1LunrapL07IW3pePDQ5/qavqef0c+OdYAELuAac4jGGkLL9rdvfyo9N9ODQAqBGmmrwGlb/R0u3xG4gMspOC5hG882CoRaaCSA8n1ff9doIQMu4PIOrus3u+8ZVNnw6e/Od5AALuDKOyz5hmqiPnfnzi1J9bSbgRWCpvvQfY307wQu4BoxJCOFaDK8rwsQmQsUIQhWW93XSIsewAVckYdLQ24F0Ui/926AARdwRRounZ6Np7GyYdN9DzdFBC7gijRc43GMlQ1U9s/6HXJNjYELuHI<<-----Removed----->>>>",
"contentType": "image/png"
}
]
}
Response
HTTP/1.1 200 OK
{
"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#teams('team-id')/channels('channel-id')/messages/$entity",
"id":"id-value",
"replyToId":null,
"etag":"id-value",
"messageType":"message",
"createdDateTime": "2019-02-04T19:58:15.511Z",
"lastModifiedDateTime":null,
"deleted":false,
"subject":null,
"summary":null,
"importance":"normal",
"locale":"en-us",
"policyViolation":null,
"from": {
"application":null,
"device":null,
"conversation":null,
"user": {
"id":"id-value",
"displayName":"John Doe",
"userIdentityType":"aadUser"
}
},
"body": {
"contentType":"html",
"content":"<div><div>\n<div><span><img height=\"250\" src=\"https://graph.microsoft.com/teams/teamId/channels/channelId/messages/id-value/hostedContents/hostedContentId/$value\" width=\"176.2295081967213\" style=\"vertical-align:bottom; width:176px; height:250px\"></span>\n\n</div>\n\n\n</div>\n</div>"
},
"attachments":[],
"mentions":[],
"reactions":[]
}
Step 4: Complete migration mode
Use the completeMigration API to finish the migration process for new and existing channels and chats. For more information, see:
Complete new team and channel migration
Use the completeMigration API to complete migration for the new team and channel
This action opens the team and channel resources for general use by team members. The action is bound to the team instance. Before you complete the team message migration, you must complete migration on all channels.
Request (end channel migration mode)
POST https://graph.microsoft.com/beta/teams/team-id/channels/channel-id/completeMigration
Response
HTTP/1.1 204 NoContent
Request (end team migration mode)
POST https://graph.microsoft.com/beta/teams/team-id/completeMigration
Response
HTTP/1.1 204 NoContent
Add team members
After completing migration of external messages, you can add a single member to a team by using the Teams UI You can also use Microsoft Graph to add single member or add members in bulk.
Request (add member)
POST https://graph.microsoft.com/beta/teams/{team-id}/members
Content-type:application/json
Content-length:30
{
"@odata.type":"#microsoft.graph.aadUserConversationMember",
"roles":[],
"user@odata.bind":"https://graph.microsoft.com/beta/users/{user-id}"
}
Response
HTTP/1.1 204 No Content
Once you complete new team and channel migration, verify migration mode completion.
Complete existing channel or chat migration
For existing channels or chats already in migration mode, use the completeMigration API to mark the migration state as completed. This process ensures that the channel or chat remains permanently available instead of being dropped after migration.
Request (complete existing channel migration)
POST https://graph.microsoft.com/beta/teams/{team-id}/channels/{channel-id}/completeMigration
Response
HTTP/1.1 204 NoContent
Request (complete existing chat migration)
POST https://graph.microsoft.com/beta/chats/{chat-id}/completeMigration
Response
HTTP/1.1 204 NoContent
Optional: Update group chat member history after migration
When you complete message migration in a group chat, you can optionally update members’ share history by using the visibleHistoryStartDateTime property in Microsoft Graph. This property sets the earliest time a chat member can view messages in a conversation. If imported messages are older than the property's value, they don’t appear unless you update the property.
To update the visibleHistoryStartDateTime property:
- Remove the member from the chat.
- Add the member back with a new
visibleHistoryStartDateTimethat includes the imported messages.
Example
Consider a scenario where the original chat was created at 10 PM, updated at 1 AM, messages were imported at 9 AM, and member A’s share history starts at 10 AM. To ensure that member A can see the 9 AM imported messages:
- Remove member A from the chat.
- Add member A with the
visibleHistoryStartDateTimeproperty set before 9 AM.
Step 5: Verify migration mode completion
Call Get channel or
Get chat to verify that the migrationMode is marked as Completed.
Tips and additional information
After calling
completeMigrationon an existing channel or chat, you can continue importing messages by using thestartMigrationAPI.You can only add team members to the new Teams after the
completeMigrationrequest returns a successful response. This rule applies only to the newly created team and standard channel.Throttling: Messages import at five RPS per channel.
If you need to correct the migration results, you must delete the Teams, repeat the steps to create the Teams and channel, and re-migrate the messages.
Note
Inline images are the only type of media supported by the import message API schema.
Code sample
| Sample name | Description | Node.js | C# | Python |
|---|---|---|---|---|
| Graph chat migration | This sample app can be used to migrate historical messages from external platforms to Teams. | View | View | NA |
See also
Platform Docs