Communication & Collaboration8 min read

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.

Published April 29, 2026
01Overview

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.


02The case for integration

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.


03Architecture

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.


04Use cases

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.


05Implementation

Step-by-step integration

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


06Code

Code example

typescriptapp/api/sanity-to-teams/route.ts
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 });
}

07Why Sanity

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 →

08Comparison

CMS approaches to Microsoft Teams

CapabilityTraditional CMSSanity
Channel notifications on publishOften 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 payloadsPage-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 alertsApproval 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 choicesPlugin-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 consistencyTeams 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.

09Next steps

Keep building

Explore related integrations to complete your content stack.

Ready to try Sanity?

See how Sanity's Content Operating System powers integrations with Microsoft Teams and 200+ other tools.