Requirements
- Target platform
- OpenClaw
- Install method
- Manual import
- Extraction
- Extract archive
- Prerequisites
- OpenClaw
- Primary doc
- SKILL.md
Microsoft Teams API integration with managed OAuth. Manage teams, channels, messages, and meetings via Microsoft Graph API. Use this skill when users want to...
Microsoft Teams API integration with managed OAuth. Manage teams, channels, messages, and meetings via Microsoft Graph API. Use this skill when users want to...
Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.
I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete.
I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run.
Access the Microsoft Teams API with managed OAuth authentication via Microsoft Graph. Manage teams, channels, messages, meetings, and access recordings and transcripts.
# List user's joined teams python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://gateway.maton.ai/microsoft-teams/v1.0/me/joinedTeams') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
https://gateway.maton.ai/microsoft-teams/{native-api-path} Replace {native-api-path} with the actual Microsoft Graph API endpoint path. The gateway proxies requests to graph.microsoft.com and automatically injects your OAuth token.
All requests require the Maton API key in the Authorization header: Authorization: Bearer $MATON_API_KEY Environment Variable: Set your API key as MATON_API_KEY: export MATON_API_KEY="YOUR_API_KEY"
Sign in or create an account at maton.ai Go to maton.ai/settings Copy your API key
Manage your Microsoft Teams OAuth connections at https://ctrl.maton.ai.
python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://ctrl.maton.ai/connections?app=microsoft-teams&status=ACTIVE') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
python <<'EOF' import urllib.request, os, json data = json.dumps({'app': 'microsoft-teams'}).encode() req = urllib.request.Request('https://ctrl.maton.ai/connections', data=data, method='POST') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') req.add_header('Content-Type', 'application/json') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://ctrl.maton.ai/connections/{connection_id}') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF Response: { "connection": { "connection_id": "fb0fdc4a-0b5a-40cf-8b92-3bdae848cde3", "status": "ACTIVE", "creation_time": "2026-02-17T09:51:21.074601Z", "last_updated_time": "2026-02-17T09:51:34.323814Z", "url": "https://connect.maton.ai/?session_token=...", "app": "microsoft-teams", "metadata": {} } } Open the returned url in a browser to complete OAuth authorization.
python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://ctrl.maton.ai/connections/{connection_id}', method='DELETE') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
If you have multiple Microsoft Teams connections, specify which one to use with the Maton-Connection header: python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://gateway.maton.ai/microsoft-teams/v1.0/me/joinedTeams') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') req.add_header('Maton-Connection', 'fb0fdc4a-0b5a-40cf-8b92-3bdae848cde3') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF If omitted, the gateway uses the default (oldest) active connection.
List Joined Teams GET /microsoft-teams/v1.0/me/joinedTeams Response: { "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#teams", "@odata.count": 1, "value": [ { "id": "b643f103-870d-4f98-a23d-e6f164fae33e", "displayName": "carvedai.com", "description": null, "isArchived": false, "tenantId": "cb83c3f9-6d16-4cf3-bd8c-ab16b37932f9" } ] } Get Team GET /microsoft-teams/v1.0/teams/{team-id}
List Channels GET /microsoft-teams/v1.0/teams/{team-id}/channels Response: { "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#teams('...')/channels", "@odata.count": 1, "value": [ { "id": "19:9fwtZjo3IM0D8bLdQqR-_oMFw1eUDlzWjPfIhNGhVd41@thread.tacv2", "createdDateTime": "2026-02-16T20:09:27.254Z", "displayName": "General", "description": null, "email": "carvedai.com473@carvedai.com", "membershipType": "standard", "isArchived": false } ] } List Private Channels GET /microsoft-teams/v1.0/teams/{team-id}/channels?$filter=membershipType eq 'private' Get Channel GET /microsoft-teams/v1.0/teams/{team-id}/channels/{channel-id} Create Channel POST /microsoft-teams/v1.0/teams/{team-id}/channels Content-Type: application/json { "displayName": "New Channel", "description": "Channel description", "membershipType": "standard" } Response: { "id": "19:3b3361df822044558a062bb1a4ac8357@thread.tacv2", "createdDateTime": "2026-02-17T20:24:33.9284462Z", "displayName": "Maton Test Channel", "description": "Channel created by Maton integration test", "membershipType": "standard", "isArchived": false } Update Channel PATCH /microsoft-teams/v1.0/teams/{team-id}/channels/{channel-id} Content-Type: application/json { "description": "Updated description" } Returns 204 No Content on success. Note: The default "General" channel cannot be updated. Delete Channel DELETE /microsoft-teams/v1.0/teams/{team-id}/channels/{channel-id} Returns 204 No Content on success.
List Channel Members GET /microsoft-teams/v1.0/teams/{team-id}/channels/{channel-id}/members Response: { "@odata.count": 1, "value": [ { "@odata.type": "#microsoft.graph.aadUserConversationMember", "id": "MCMjMiMj...", "roles": ["owner"], "displayName": "Kevin Kim", "userId": "5f56d55b-2ffb-448d-982a-b52547431f71", "email": "richard@carvedai.com" } ] }
List Channel Messages GET /microsoft-teams/v1.0/teams/{team-id}/channels/{channel-id}/messages Send Message to Channel POST /microsoft-teams/v1.0/teams/{team-id}/channels/{channel-id}/messages Content-Type: application/json { "body": { "content": "Hello World" } } Response: { "id": "1771359569239", "replyToId": null, "messageType": "message", "createdDateTime": "2026-02-17T20:19:29.239Z", "importance": "normal", "locale": "en-us", "from": { "user": { "id": "5f56d55b-2ffb-448d-982a-b52547431f71", "displayName": "Kevin Kim", "userIdentityType": "aadUser", "tenantId": "cb83c3f9-6d16-4cf3-bd8c-ab16b37932f9" } }, "body": { "contentType": "text", "content": "Hello World" }, "channelIdentity": { "teamId": "b643f103-870d-4f98-a23d-e6f164fae33e", "channelId": "19:9fwtZjo3IM0D8bLdQqR-_oMFw1eUDlzWjPfIhNGhVd41@thread.tacv2" } } Send HTML Message POST /microsoft-teams/v1.0/teams/{team-id}/channels/{channel-id}/messages Content-Type: application/json { "body": { "contentType": "html", "content": "<h1>Hello</h1><p>This is <strong>formatted</strong> content.</p>" } } Reply to Message POST /microsoft-teams/v1.0/teams/{team-id}/channels/{channel-id}/messages/{message-id}/replies Content-Type: application/json { "body": { "content": "This is a reply" } } List Message Replies GET /microsoft-teams/v1.0/teams/{team-id}/channels/{channel-id}/messages/{message-id}/replies Edit Message PATCH /microsoft-teams/v1.0/teams/{team-id}/channels/{channel-id}/messages/{message-id} Content-Type: application/json { "body": { "content": "Updated message content" } } Returns 204 No Content on success.
List Team Members GET /microsoft-teams/v1.0/teams/{team-id}/members Response: { "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#teams('...')/members", "@odata.count": 1, "value": [ { "@odata.type": "#microsoft.graph.aadUserConversationMember", "id": "MCMjMSMj...", "roles": ["owner"], "displayName": "Kevin Kim", "userId": "5f56d55b-2ffb-448d-982a-b52547431f71", "email": "richard@carvedai.com", "tenantId": "cb83c3f9-6d16-4cf3-bd8c-ab16b37932f9" } ] }
Get User Presence GET /microsoft-teams/v1.0/me/presence Response: { "id": "5f56d55b-2ffb-448d-982a-b52547431f71", "availability": "Offline", "activity": "Offline", "outOfOfficeSettings": { "message": null, "isOutOfOffice": false } } Availability values: Available, Busy, DoNotDisturb, Away, Offline Get User Presence by ID GET /microsoft-teams/v1.0/users/{user-id}/presence Returns presence information for a specific user by their ID.
List Channel Tabs GET /microsoft-teams/v1.0/teams/{team-id}/channels/{channel-id}/tabs Response: { "@odata.count": 2, "value": [ { "id": "ee0b3e8b-dfc8-4945-a45d-28ceaf787d92", "displayName": "Notes", "webUrl": "https://teams.microsoft.com/l/entity/..." }, { "id": "3ed5b337-c2c9-4d5d-b7b4-84ff09a8fc1c", "displayName": "Files", "webUrl": "https://teams.microsoft.com/l/entity/..." } ] }
List Installed Apps GET /microsoft-teams/v1.0/teams/{team-id}/installedApps
Create Meeting POST /microsoft-teams/v1.0/me/onlineMeetings Content-Type: application/json { "subject": "Team Sync", "startDateTime": "2026-02-18T10:00:00Z", "endDateTime": "2026-02-18T11:00:00Z" } Response: { "id": "MSo1ZjU2ZDU1Yi0yZmZi...", "subject": "Team Sync", "startDateTime": "2026-02-18T10:00:00Z", "endDateTime": "2026-02-18T11:00:00Z", "joinUrl": "https://teams.microsoft.com/l/meetup-join/...", "joinWebUrl": "https://teams.microsoft.com/l/meetup-join/...", "meetingCode": "28636743235745", "joinMeetingIdSettings": { "joinMeetingId": "28636743235745", "passcode": "qh37NK9V", "isPasscodeRequired": true }, "participants": { "organizer": { "upn": "richard@carvedai.com", "role": "presenter" } } } The joinUrl can be shared with attendees to join the meeting. Get Meeting GET /microsoft-teams/v1.0/me/onlineMeetings/{meeting-id} Find Meeting by Join URL GET /microsoft-teams/v1.0/me/onlineMeetings?$filter=JoinWebUrl eq '{encoded-join-url}' Note: Microsoft Graph requires a filter to query meetings. You cannot list all meetings without filtering by JoinWebUrl. List Calendar Events (includes scheduled meetings) GET /microsoft-teams/v1.0/me/calendar/events?$top=10 Scheduled Teams meetings appear as calendar events with isOnlineMeeting: true. Delete Meeting DELETE /microsoft-teams/v1.0/me/onlineMeetings/{meeting-id} Returns 204 No Content on success. Create Meeting with Attendees POST /microsoft-teams/v1.0/me/onlineMeetings Content-Type: application/json { "subject": "Project Review", "startDateTime": "2026-02-18T14:00:00Z", "endDateTime": "2026-02-18T15:00:00Z", "participants": { "attendees": [ { "upn": "attendee@example.com", "role": "attendee" } ] } } List Meeting Recordings GET /microsoft-teams/v1.0/me/onlineMeetings/{meeting-id}/recordings Returns a list of recordings for a meeting (available after the meeting has ended and recording was enabled). Get Meeting Recording GET /microsoft-teams/v1.0/me/onlineMeetings/{meeting-id}/recordings/{recording-id} List Meeting Transcripts GET /microsoft-teams/v1.0/me/onlineMeetings/{meeting-id}/transcripts Returns a list of transcripts for a meeting (available after the meeting has ended and transcription was enabled). Get Meeting Transcript GET /microsoft-teams/v1.0/me/onlineMeetings/{meeting-id}/transcripts/{transcript-id} List Attendance Reports GET /microsoft-teams/v1.0/me/onlineMeetings/{meeting-id}/attendanceReports Returns attendance reports for a meeting (available after the meeting has ended). Get Attendance Report GET /microsoft-teams/v1.0/me/onlineMeetings/{meeting-id}/attendanceReports/{report-id}
List User Chats GET /microsoft-teams/v1.0/me/chats Get Chat GET /microsoft-teams/v1.0/chats/{chat-id} List Chat Messages GET /microsoft-teams/v1.0/chats/{chat-id}/messages Send Chat Message POST /microsoft-teams/v1.0/chats/{chat-id}/messages Content-Type: application/json { "body": { "content": "Hello in chat" } }
Microsoft Graph uses OData-style pagination with @odata.nextLink: GET /microsoft-teams/v1.0/me/joinedTeams?$top=10 Response includes pagination link when more results exist: { "value": [...], "@odata.nextLink": "https://graph.microsoft.com/v1.0/me/joinedTeams?$skiptoken=..." } Use the $top parameter to limit results per page.
$top=10 - Limit results $skip=20 - Skip results $select=id,displayName - Select specific fields $filter=membershipType eq 'private' - Filter results $orderby=displayName - Sort results
const response = await fetch( 'https://gateway.maton.ai/microsoft-teams/v1.0/me/joinedTeams', { headers: { 'Authorization': `Bearer ${process.env.MATON_API_KEY}` } } ); const data = await response.json();
import os import requests response = requests.get( 'https://gateway.maton.ai/microsoft-teams/v1.0/me/joinedTeams', headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'} ) data = response.json()
import os import requests team_id = "your-team-id" channel_id = "your-channel-id" response = requests.post( f'https://gateway.maton.ai/microsoft-teams/v1.0/teams/{team_id}/channels/{channel_id}/messages', headers={ 'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}', 'Content-Type': 'application/json' }, json={'body': {'content': 'Hello from Maton!'}} ) data = response.json()
Uses Microsoft Graph API v1.0 Messages are sent as the authenticated user (not as a bot) - the from.user field shows the actual user identity Team IDs are GUIDs (e.g., b643f103-870d-4f98-a23d-e6f164fae33e) Channel IDs include thread suffix (e.g., 19:9fwtZjo3IM0D8bLdQqR-_oMFw1eUDlzWjPfIhNGhVd41@thread.tacv2) Message IDs are timestamps (e.g., 1771359569239) Message body content types: text (default) or html Channel membership types: standard, private, shared The default "General" channel cannot be updated or deleted Only me endpoint is supported for listing joined teams (not arbitrary user IDs) IMPORTANT: When using curl commands, use curl -g when URLs contain brackets to disable glob parsing IMPORTANT: When piping curl output to jq or other commands, environment variables like $MATON_API_KEY may not expand correctly in some shell environments
StatusMeaning400Missing Microsoft Teams connection or invalid request401Invalid or missing Maton API key403Insufficient permissions for the requested resource404Team, channel, or message not found429Rate limited (Microsoft Graph throttling)4xx/5xxPassthrough error from Microsoft Graph API
Microsoft Teams API Overview Microsoft Graph API Reference Channel Resource ChatMessage Resource Team Resource Maton Community Maton Support
Code helpers, APIs, CLIs, browser automation, testing, and developer operations.
Largest current source with strong distribution and engagement signals.