Documentation 29
Microsoft Teams API quickstart · 3 min read
The same story, in Graph's dialect.
The Microsoft Teams surface of Microsoft Graph v1.0 — teams, channels, messages, replies, members, and the tenant's users — over the same simulated data set the Slack host serves. Byte-identical message text, one canonical story: the incident-bridge burst brackets a real tracker incident, review threads echo real PRs, release announcements cite fetchable tags.
Coverage, hosts and pinned snapshots for Microsoft Teams — 13 of 13 read surfaces served and verified.
01 / Base URL + auth
A Graph tenant, any token.
Point requests at https://graph.sandboxapis.dev — clients target graph.microsoft.com, so graph. is the drop-in prefix (teams.sandboxapis.dev aliases the same host). Paths are Graph's own: /v1.0/… with OData query parameters and @odata.nextLink paging. Auth is a Bearer token — real Graph wants an Entra JWT; here any value passes, but the header must be present: its absence answers Graph's real 401 (InvalidAuthenticationToken), exactly as captured live.
curl -H 'Authorization: Bearer any-token' \
"https://graph.sandboxapis.dev/v1.0/me/joinedTeams"Using a key? Keys & rate limits → — a SandboxAPIs key rides the same Bearer slot and lifts the anonymous limit.
02 / The reads that matter
Teams, channels, messages, people.
# The teams the service identity belongs to — one per engineering team,
# plus the org-wide team holding #agora, #incident-bridge, and #releases
curl -H 'Authorization: Bearer any-token' "https://graph.sandboxapis.dev/v1.0/me/joinedTeams"
# A team's channels
curl -H 'Authorization: Bearer any-token' \
"https://graph.sandboxapis.dev/v1.0/teams/TEAM_ID/channels"
# Channel messages (default 20 per page; walk @odata.nextLink)
curl -H 'Authorization: Bearer any-token' \
"https://graph.sandboxapis.dev/v1.0/teams/TEAM_ID/channels/CHANNEL_ID/messages"
# A thread's replies, newest first
curl -H 'Authorization: Bearer any-token' \
"https://graph.sandboxapis.dev/v1.0/teams/TEAM_ID/channels/CHANNEL_ID/messages/MESSAGE_ID/replies"
# The tenant's users — emails join against every other host's rosters
curl -H 'Authorization: Bearer any-token' "https://graph.sandboxapis.dev/v1.0/users?$top=10"03 / A real response
Live from the incident bridge.
{
"@odata.context": "https://graph.sandboxapis.dev/v1.0/$metadata#teams('31837fb8-c814-42ba-8775-01dedad6c921')/channels('19%3Ae5b377c202622bec6934aec07c160755%40thread.tacv2')/messages",
"@odata.count": 1,
"value": [
{
"id": "1781455608488",
"replyToId": null,
"etag": "1781455608488",
"messageType": "message",
"createdDateTime": "2026-06-14T16:46:48.488Z",
"lastModifiedDateTime": "2026-06-14T16:46:48.488Z",
"lastEditedDateTime": null,
"deletedDateTime": null,
"subject": null,
"summary": null,
"chatId": null,
"importance": "normal",
"locale": "en-us",
"webUrl": "https://teams.microsoft.com/l/message/19%3Ae5b377c202622bec6934aec07c160755%40thread.tacv2/1781455608488?groupId=31837fb8-c814-42ba-8775-01dedad6c921&tenantId=e4de0213-744a-45dd-8ffe-e7b19441c4d6&createdTime=1781455608488&parentMessageId=1781455608488",
"policyViolation": null,
"eventDetail": null,
"from": {
"application": null,
"device": null,
"user": {
"id": "bd041599-64ea-45fb-8aaf-fac798df2d3a",
"displayName": "Cassandra",
"userIdentityType": "aadUser"
}
},
"body": {
"contentType": "text",
"content": "schema marks a nullable field as required. paging whoever's closest to the logger."
},
"channelIdentity": {
"teamId": "31837fb8-c814-42ba-8775-01dedad6c921",
"channelId": "19:e5b377c202622bec6934aec07c160755@thread.tacv2"
},
"attachments": [],
"mentions": [],
"reactions": [],
"messageHistory": []
}
]
}04 / Pin a snapshot
Deterministic CI.
The *.snap. base URL is byte-identical on every request — and teams-v1 shares its recipe with slack-2026-08, so a pinned cross-dialect messaging fixture is one artifact, not two universes.
# reproducible in CI
export GRAPH_BASE_URL=https://teams-v1.snap.sandboxapis.dev/v1.0/Tour the universe → · Coverage manifest → · Versioning & pinning →