🎁 Get the FREE AI Skills Starter Guide β€” Subscribe β†’
BytesAgainBytesAgain
πŸ¦€ ClawHub

Microsoft Teams

by @byungkyu

Microsoft Teams API integration with managed OAuth. Manage teams, channels, messages, and meetings via Microsoft Graph API. Use this skill when users want to...

Versionv1.0.1
Downloads3,182
Stars⭐ 2
TERMINAL
clawhub install microsoft-teams

πŸ“– About This Skill


name: microsoft-teams description: | Microsoft Teams API integration with managed OAuth. Manage teams, channels, messages, and meetings via Microsoft Graph API. Use this skill when users want to list teams, create channels, send messages, schedule meetings, or access meeting recordings and transcripts. For other third party apps, use the api-gateway skill (https://clawhub.ai/byungkyu/api-gateway). compatibility: Requires network access and valid Maton API key metadata: author: maton version: "1.0" clawdbot: emoji: 🧠 homepage: "https://maton.ai" requires: env: - MATON_API_KEY

Microsoft Teams

Access the Microsoft Teams API with managed OAuth authentication via Microsoft Graph. Manage teams, channels, messages, meetings, and access recordings and transcripts.

Quick Start

# List user's joined teams
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.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

Base URL

https://api.maton.ai/microsoft-teams/{native-api-path}

Maton proxies requests to graph.microsoft.com and automatically injects your OAuth token.

Authentication

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"

Getting Your API Key

1. Sign in or create an account at maton.ai 2. Go to maton.ai/settings 3. Copy your API key

Connection Management

Manage your Microsoft Teams OAuth connections at https://api.maton.ai.

List Connections

python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.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

Create Connection

python <<'EOF'
import urllib.request, os, json
data = json.dumps({'app': 'microsoft-teams'}).encode()
req = urllib.request.Request('https://api.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

Get Connection

python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.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": "{connection_id}",
    "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.

Delete Connection

python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.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

Specifying Connection

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://api.maton.ai/microsoft-teams/v1.0/me/joinedTeams')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Maton-Connection', '{connection_id}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

If you have multiple connections, always include this header to ensure requests go to the intended account.

Security & Permissions

  • Access is scoped to teams, channels, messages, and meetings via Microsoft Graph API within the connected Microsoft Teams account.
  • All write operations require explicit user approval. Before executing any create, update, or delete call, confirm the target resource and intended effect with the user.
  • API Reference

    Teams

    #### 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}
    

    Channels

    #### 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.

    Channel Members

    #### 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"
        }
      ]
    }
    

    Messages

    #### 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": "

    Hello

    This is formatted content.

    " } }

    #### 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.

    Team Members

    #### 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"
        }
      ]
    }
    

    Presence

    #### 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.

    Tabs

    #### 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/..."
        }
      ]
    }
    

    Apps

    #### List Installed Apps

    GET /microsoft-teams/v1.0/teams/{team-id}/installedApps
    

    Online Meetings

    #### 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}
    

    Chats

    #### 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" } }

    Pagination

    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.

    OData Query Parameters

  • $top=10 - Limit results
  • $skip=20 - Skip results
  • $select=id,displayName - Select specific fields
  • $filter=membershipType eq 'private' - Filter results
  • $orderby=displayName - Sort results
  • Code Examples

    JavaScript

    const response = await fetch(
      'https://api.maton.ai/microsoft-teams/v1.0/me/joinedTeams',
      {
        headers: {
          'Authorization': Bearer ${process.env.MATON_API_KEY}
        }
      }
    );
    const data = await response.json();
    

    Python

    import os
    import requests

    response = requests.get( 'https://api.maton.ai/microsoft-teams/v1.0/me/joinedTeams', headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'} ) data = response.json()

    Send Message Example (Python)

    import os
    import requests

    team_id = "your-team-id" channel_id = "your-channel-id"

    response = requests.post( f'https://api.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()

    Notes

  • 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
  • Error Handling

    | Status | Meaning | |--------|---------| | 400 | Missing Microsoft Teams connection or invalid request | | 401 | Invalid or missing Maton API key | | 403 | Insufficient permissions for the requested resource | | 404 | Team, channel, or message not found | | 429 | Rate limited (Microsoft Graph throttling) | | 4xx/5xx | Passthrough error from Microsoft Graph API |

    Resources

  • Microsoft Teams API Overview
  • Microsoft Graph API Reference
  • Channel Resource
  • ChatMessage Resource
  • Team Resource
  • Maton Community
  • Maton Support
  • πŸ’‘ Examples

    # List user's joined teams
    python <<'EOF'
    import urllib.request, os, json
    req = urllib.request.Request('https://api.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
    

    πŸ“‹ Tips & Best Practices

  • 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