Skip to main content

Overview

The Chats API provides operations to manage one-on-one and group chats in Microsoft Teams. Access through graphClient.Chats.

Request Builder

public ChatsRequestBuilder Chats { get; }
Accessed via: 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

Build docs developers (and LLMs) love