Overview
The Chats API provides operations to manage one-on-one and group chats in Microsoft Teams. Access throughgraphClient.Chats.
Request Builder
public ChatsRequestBuilder Chats { get; }
graphClient.Chats
Operations
List Chats
Retrieve chats for the current user.var chats = await graphClient.Me.Chats.GetAsync();
foreach (var chat in chats.Value)
{
Console.WriteLine($"{chat.Topic ?? "(No topic)"}");
Console.WriteLine($" Type: {chat.ChatType}");
Console.WriteLine($" Created: {chat.CreatedDateTime}");
Console.WriteLine($" Web URL: {chat.WebUrl}");
}
Get Chat by ID
var chat = await graphClient.Chats["chat-id"].GetAsync();
Console.WriteLine($"Chat: {chat.Topic}");
Console.WriteLine($"Type: {chat.ChatType}"); // oneOnOne, group, meeting
Create Chat
// One-on-one chat
var oneOnOneChat = new Chat
{
ChatType = ChatType.OneOnOne,
Members = new List<ConversationMember>
{
new AadUserConversationMember
{
Roles = new List<string> { "owner" },
AdditionalData = new Dictionary<string, object>
{
{
"[email protected]",
$"https://graph.microsoft.com/v1.0/users/{currentUserId}"
}
}
},
new AadUserConversationMember
{
Roles = new List<string> { "owner" },
AdditionalData = new Dictionary<string, object>
{
{
"[email protected]",
$"https://graph.microsoft.com/v1.0/users/{otherUserId}"
}
}
}
}
};
var chat = await graphClient.Chats.PostAsync(oneOnOneChat);
// Group chat
var groupChat = new Chat
{
ChatType = ChatType.Group,
Topic = "Project Discussion",
Members = new List<ConversationMember>
{
new AadUserConversationMember
{
Roles = new List<string> { "owner" },
AdditionalData = new Dictionary<string, object>
{
{ "[email protected]", $"https://graph.microsoft.com/v1.0/users/{userId1}" }
}
},
new AadUserConversationMember
{
Roles = new List<string> { "owner" },
AdditionalData = new Dictionary<string, object>
{
{ "[email protected]", $"https://graph.microsoft.com/v1.0/users/{userId2}" }
}
}
}
};
var chat = await graphClient.Chats.PostAsync(groupChat);
Update Chat
var updateChat = new Chat
{
Topic = "Updated Chat Topic"
};
await graphClient.Chats["chat-id"].PatchAsync(updateChat);
Delete Chat (Soft Delete)
await graphClient.Chats["chat-id"].DeleteAsync();
Members
List Members
var members = await graphClient.Chats["chat-id"].Members.GetAsync();
foreach (var member in members.Value)
{
if (member is AadUserConversationMember userMember)
{
Console.WriteLine($"{userMember.DisplayName}");
Console.WriteLine($" Email: {userMember.Email}");
Console.WriteLine($" Roles: {string.Join(", ", userMember.Roles)}");
}
}
Add Member
var newMember = new AadUserConversationMember
{
Roles = new List<string> { "owner" },
AdditionalData = new Dictionary<string, object>
{
{
"[email protected]",
$"https://graph.microsoft.com/v1.0/users/{userId}"
}
}
};
await graphClient.Chats["chat-id"].Members.PostAsync(newMember);
Remove Member
await graphClient.Chats["chat-id"].Members["membership-id"].DeleteAsync();
Messages
List Messages
var messages = await graphClient.Chats["chat-id"].Messages.GetAsync();
foreach (var message in messages.Value)
{
Console.WriteLine($"{message.From.User.DisplayName}: {message.Body.Content}");
Console.WriteLine($"Created: {message.CreatedDateTime}");
}
// Get recent messages
var recentMessages = await graphClient.Chats["chat-id"]
.Messages
.GetAsync(config =>
{
config.QueryParameters.Top = 50;
config.QueryParameters.Orderby = new[] { "createdDateTime desc" };
});
Send Message
var newMessage = new ChatMessage
{
Body = new ItemBody
{
ContentType = BodyType.Html,
Content = "<p>Hello! Check out this document.</p>"
}
};
var message = await graphClient.Chats["chat-id"]
.Messages
.PostAsync(newMessage);
Send Message with Mention
var messageWithMention = new ChatMessage
{
Body = new ItemBody
{
ContentType = BodyType.Html,
Content = "<p>Hey <at id='0'>John</at>, can you review this?</p>"
},
Mentions = new List<ChatMessageMention>
{
new ChatMessageMention
{
Id = 0,
MentionText = "John",
Mentioned = new ChatMessageMentionedIdentitySet
{
User = new TeamworkUserIdentity
{
Id = "user-id",
DisplayName = "John Doe"
}
}
}
}
};
await graphClient.Chats["chat-id"].Messages.PostAsync(messageWithMention);
Send Message with Attachment
var messageWithAttachment = new ChatMessage
{
Body = new ItemBody
{
ContentType = BodyType.Html,
Content = "<p>Here's the document</p><attachment id='attachment-id'></attachment>"
},
Attachments = new List<ChatMessageAttachment>
{
new ChatMessageAttachment
{
Id = "attachment-id",
ContentType = "reference",
ContentUrl = "https://contoso.sharepoint.com/sites/project/document.pdf",
Name = "document.pdf"
}
}
};
await graphClient.Chats["chat-id"].Messages.PostAsync(messageWithAttachment);
Get Message
var message = await graphClient.Chats["chat-id"]
.Messages["message-id"]
.GetAsync();
Update Message
var updateMessage = new ChatMessage
{
Body = new ItemBody
{
ContentType = BodyType.Html,
Content = "<p>Updated message content</p>"
}
};
await graphClient.Chats["chat-id"]
.Messages["message-id"]
.PatchAsync(updateMessage);
Delete Message (Soft Delete)
await graphClient.Chats["chat-id"]
.Messages["message-id"]
.SoftDelete
.PostAsync();
Undo Soft Delete
await graphClient.Chats["chat-id"]
.Messages["message-id"]
.UndoSoftDelete
.PostAsync();
Tabs
List Tabs
var tabs = await graphClient.Chats["chat-id"].Tabs.GetAsync();
foreach (var tab in tabs.Value)
{
Console.WriteLine($"{tab.DisplayName} - {tab.WebUrl}");
}
Add Tab
var newTab = new TeamsTab
{
DisplayName = "Project Plan",
AdditionalData = new Dictionary<string, object>
{
{
"[email protected]",
"https://graph.microsoft.com/v1.0/appCatalogs/teamsApps/com.microsoft.teamspace.tab.planner"
}
},
Configuration = new TeamsTabConfiguration
{
EntityId = "plan-id",
ContentUrl = "https://tasks.office.com/...",
WebsiteUrl = "https://tasks.office.com/..."
}
};
await graphClient.Chats["chat-id"].Tabs.PostAsync(newTab);
Installed Apps
List Installed Apps
var apps = await graphClient.Chats["chat-id"]
.InstalledApps
.GetAsync(config =>
{
config.QueryParameters.Expand = new[] { "teamsAppDefinition" };
});
foreach (var app in apps.Value)
{
Console.WriteLine($"{app.TeamsAppDefinition.DisplayName}");
}
Install App
var appInstallation = new TeamsAppInstallation
{
AdditionalData = new Dictionary<string, object>
{
{
"[email protected]",
$"https://graph.microsoft.com/v1.0/appCatalogs/teamsApps/{appId}"
}
}
};
await graphClient.Chats["chat-id"].InstalledApps.PostAsync(appInstallation);
Uninstall App
await graphClient.Chats["chat-id"]
.InstalledApps["installation-id"]
.DeleteAsync();
Pinned Messages
List Pinned Messages
var pinnedMessages = await graphClient.Chats["chat-id"]
.PinnedMessages
.GetAsync();
foreach (var pinnedMessage in pinnedMessages.Value)
{
Console.WriteLine($"Message: {pinnedMessage.Message.Body.Content}");
}
Pin Message
var pin = new PinnedChatMessageInfo
{
Message = new ChatMessage
{
Id = "message-id"
}
};
await graphClient.Chats["chat-id"].PinnedMessages.PostAsync(pin);
Unpin Message
await graphClient.Chats["chat-id"]
.PinnedMessages["pinned-message-id"]
.DeleteAsync();
Permissions Grants
List Permission Grants
var grants = await graphClient.Chats["chat-id"]
.PermissionGrants
.GetAsync();
Operations
Hide Chat for User
await graphClient.Chats["chat-id"].HideForUser.PostAsync(new HideForUserPostRequestBody
{
User = new TeamworkUserIdentity
{
Id = "user-id"
}
});
Unhide Chat for User
await graphClient.Chats["chat-id"].UnhideForUser.PostAsync(new UnhideForUserPostRequestBody
{
User = new TeamworkUserIdentity
{
Id = "user-id"
}
});
Mark Chat as Read
await graphClient.Chats["chat-id"].MarkChatReadForUser.PostAsync(new MarkChatReadForUserPostRequestBody
{
User = new TeamworkUserIdentity
{
Id = "user-id"
}
});
Mark Chat as Unread
await graphClient.Chats["chat-id"].MarkChatUnreadForUser.PostAsync(new MarkChatUnreadForUserPostRequestBody
{
User = new TeamworkUserIdentity
{
Id = "user-id"
},
LastMessageReadDateTime = DateTime.UtcNow.AddMinutes(-10)
});
Associated Team
For meeting chats associated with a team.var team = await graphClient.Chats["chat-id"]
.OnlineMeeting
.GetAsync();
Chat Types
OneOnOne
- Private conversation between two people
- Cannot add more members
- Topic cannot be set
Group
- Conversation between multiple people
- Members can be added/removed
- Topic can be customized
Meeting
- Associated with Teams meeting
- Created automatically for meetings
Common Patterns
Find Chat by Participants
var chats = await graphClient.Me.Chats.GetAsync();
foreach (var chat in chats.Value)
{
var members = await graphClient.Chats[chat.Id].Members.GetAsync();
// Check if chat contains specific users
var userIds = members.Value
.OfType<AadUserConversationMember>()
.Select(m => m.UserId);
if (userIds.Contains("target-user-id"))
{
Console.WriteLine($"Found chat: {chat.Id}");
}
}
Send Adaptive Card
var adaptiveCard = @"{
""$schema"": ""http://adaptivecards.io/schemas/adaptive-card.json"",
""type"": ""AdaptiveCard"",
""version"": ""1.4"",
""body"": [
{
""type"": ""TextBlock"",
""text"": ""Hello from bot!""
}
]
}";
var message = new ChatMessage
{
Body = new ItemBody
{
ContentType = BodyType.Html,
Content = $"<attachment id='adaptive-card'></attachment>"
},
Attachments = new List<ChatMessageAttachment>
{
new ChatMessageAttachment
{
Id = "adaptive-card",
ContentType = "application/vnd.microsoft.card.adaptive",
Content = adaptiveCard
}
}
};
Error Handling
using Microsoft.Graph.Models.ODataErrors;
try
{
var chat = await graphClient.Chats["chat-id"].GetAsync();
}
catch (ODataError error)
{
if (error.Error.Code == "NotFound")
{
Console.WriteLine("Chat not found");
}
else if (error.Error.Code == "Forbidden")
{
Console.WriteLine("Access denied to chat");
}
else
{
Console.WriteLine($"Error: {error.Error.Message}");
}
}
See Also
Chat Model
Chat resource properties
Channels API
Channel operations
Teams API
Team operations
Chat Messages
Message resource
