How to Integrate Microsoft Teams with Your Headless CMS
Send publish alerts, release notes, and content review requests from your headless CMS into Microsoft Teams channels the moment content changes.
What is Microsoft Teams?
Microsoft Teams is Microsoft’s collaboration platform for chat, meetings, calling, channels, files, and internal apps. It’s part of Microsoft 365 and is used by more than 320 million monthly active users across enterprises, schools, public sector teams, and growing companies. Teams also supports app integrations through Incoming Webhooks, Microsoft Graph, Bot Framework, Adaptive Cards, and Teams Toolkit.
Why integrate Microsoft Teams with a headless CMS?
When content changes, the people who need to act on it are often already in Teams. A product marketer needs to know when a launch page is ready. A support lead needs release notes before customers ask questions. A legal reviewer needs a clear approval request, not a buried email thread.
Connecting Microsoft Teams to a headless CMS turns those content events into channel messages, review cards, and status updates. Instead of copying URLs into chat after every publish, you can send a Teams card with the title, owner, locale, publish time, and preview link. For a release with 40 localized entries, that can replace dozens of manual pings with one structured notification per market or channel.
The quality of the integration depends on the content shape. If your source is a page blob, your Teams message has to scrape HTML or guess what changed. With Sanity’s AI Content Operating System, content is structured as typed JSON in the Content Lake, so a webhook or Function can pull exactly the fields Teams needs. The trade-off is setup time. You’ll need a Teams webhook, Graph app, or bot configuration, plus a clear rule for which content events should notify which channels.
Architecture overview
A typical Sanity and Microsoft Teams integration starts when an editor publishes, updates, or deletes content in Sanity Studio. A Sanity webhook fires on that mutation, often filtered with GROQ so only specific document types or publish events trigger the flow. For example, you might notify Teams only when a document of type releaseNote reaches status == "approved". The webhook can call a Sanity Function or your own middleware. The Function receives the mutation payload, uses @sanity/client to query the Content Lake with GROQ, and projects only the fields needed for Teams, such as title, slug, product name, author, release date, and reviewer mentions. If the Teams message needs referenced data, GROQ can join it in one query. From there, the server-side code calls Microsoft Teams. For simple channel notifications, post an Adaptive Card to a Teams Incoming Webhook URL. For richer workflows, use Microsoft Graph, such as POST /teams/{team-id}/channels/{channel-id}/messages, but note that normal channel message posting requires delegated ChannelMessage.Send permissions. For app-only and proactive flows, use Bot Framework instead. The end user sees the result as a channel message, card, or bot notification inside Teams, with links back to Sanity Studio, a preview URL, or the published page.
Common use cases
Release note alerts
Post a Teams card to #product-updates when a release note is published, including product area, version, owner, and live URL.
Editorial review requests
Send a review card to a legal, brand, or localization channel when content moves into an approval state.
Localization status updates
Notify regional Teams channels when translated content is ready, missing, or blocked for a specific locale.
Incident and support comms
Push approved outage updates, support macros, or FAQ changes into Teams so customer-facing teams see the latest message.
Step-by-step integration
- 1
Set up Microsoft Teams access
Choose the Teams delivery method. For simple channel posts, create an Incoming Webhook in the target channel or a Teams Workflow with a webhook trigger. For richer apps, register an app in Microsoft Entra ID, configure Microsoft Graph permissions, or create a Bot Framework app with Teams as a channel.
- 2
Install the packages you need
For a TypeScript webhook handler, install @sanity/client. If you use Microsoft Graph, also install @microsoft/microsoft-graph-client and an auth library such as @azure/identity. For Incoming Webhooks, the Teams endpoint is called with fetch and a JSON card payload.
- 3
Model the content in Sanity Studio
Define the schema fields Teams needs, such as title, slug, status, product, owner, releaseDate, locale, and notificationChannels. Because schemas are code, you can review field changes in Git before they affect notifications.
- 4
Create the trigger in Sanity
Add a webhook filtered by document type and state, or use a Sanity Function triggered by content mutations. A GROQ filter like _type == "releaseNote" && status == "approved" keeps noisy draft edits out of Teams.
- 5
Send the Teams message
In the handler, fetch the full document from the Content Lake with GROQ, format an Adaptive Card, and POST it to the Teams webhook URL. If you need threaded replies, user mentions, or channel message APIs, use Microsoft Graph and plan for delegated auth.
- 6
Test the full path
Publish a test document in Sanity Studio, confirm the webhook delivery log, check the Teams channel, and verify links to the preview, production page, and Sanity Studio edit screen. Add retry logging before using it for launch content.
Code example
import { createClient } from '@sanity/client';
const sanity = createClient({
projectId: process.env.SANITY_PROJECT_ID!,
dataset: process.env.SANITY_DATASET!,
apiVersion: '2025-02-19',
token: process.env.SANITY_READ_TOKEN!,
useCdn: false,
});
export async function POST(req: Request) {
const payload = await req.json();
const id = payload._id;
const doc = await sanity.fetch(
`*[_id == $id][0]{
title,
"url": "https://example.com/releases/" + slug.current,
releaseDate,
"product": product->name
}`,
{ id }
);
if (!doc) return Response.json({ skipped: true });
await fetch(process.env.TEAMS_WEBHOOK_URL!, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
type: 'message',
attachments: [{
contentType: 'application/vnd.microsoft.card.adaptive',
content: {
type: 'AdaptiveCard',
version: '1.4',
body: [
{ type: 'TextBlock', weight: 'Bolder', text: `Published: ${doc.title}` },
{ type: 'TextBlock', text: `${doc.product} · ${doc.releaseDate}` }
],
actions: [{ type: 'Action.OpenUrl', title: 'View release', url: doc.url }]
}
}]
}),
});
return Response.json({ ok: true });
}How Sanity + Microsoft Teams works
Build your Microsoft Teams integration on Sanity
Sanity gives you the structured content foundation, real-time event system, and flexible APIs to connect Microsoft Teams to the content operations your teams already run.
Start building free →CMS approaches to Microsoft Teams
| Capability | Traditional CMS | Sanity |
|---|---|---|
| Channel notifications on publish | Often needs plugins, cron jobs, or custom code that watches published pages after the fact. | Webhooks and Functions can trigger on specific mutations, with GROQ filters for document type, status, locale, and other fields. |
| Teams card payloads | Page-centric content can force the integration to scrape titles, summaries, and URLs from rendered HTML. | GROQ can return a small card-ready JSON payload, including joined references like product, owner, and campaign. |
| Editorial workflow alerts | Approval steps may be locked to the editing UI, so Teams only gets a final publish alert. | Sanity Studio fields, Tasks, Comments, Content Releases, webhooks, and Functions can route review messages to the right Teams channel. |
| Authentication and delivery choices | Plugin-based integrations may support only one Teams method, often Incoming Webhooks. | Functions can host the server-side call without separate infrastructure. You still need to choose Teams Incoming Webhooks, Microsoft Graph delegated auth, or Bot Framework based on the workflow. |
| Multi-channel consistency | Teams messages, website copy, and support docs can drift if teams paste content manually. | The same structured content can feed web, mobile, Teams, and production AI agents through Agent Context. |
Keep building
Explore related integrations to complete your content stack.
Sanity + Slack
Send publish alerts, review requests, and release updates from Sanity into Slack channels.
Sanity + Twilio
Trigger SMS, WhatsApp, or voice notifications from structured content events in Sanity.
Sanity + Zendesk
Sync approved help content and support updates from Sanity into customer service workflows.