Microsoft Teams webhooks: Workflows, Adaptive Cards and outgoing webhooks
To send messages into Microsoft Teams in 2026, create a webhook with the Workflows app, since Office 365 connectors stopped working in May 2026. Preview the exact JSON your code sends in a free webhooks.sh bin first: no signup, 48 hours, 100 requests a day.
Most people searching for a Microsoft Teams webhook want to post alerts or notifications into a channel, and the old Office 365 connector URLs stopped working in May 2026, so new ones have to come from the Workflows app. The safest way to get the payload right before you spam a channel is to send it to a free bin first, read the exact JSON your code produced, and then swap in the Teams URL. If you're going the other direction, this page also covers Teams outgoing webhooks.
Connectors are retired, Workflows replaced them
Microsoft announced the retirement of Office 365 connectors on July 3, 2024, pushed the deadline back several times, and rolled out the final shutdown from May 18 to May 22, 2026. Old connector webhook URLs no longer post messages. The replacement is a Teams workflow webhook built on Power Automate, which posts every message as the Workflows bot and doesn't let you customize the bot's name or icon.
| Option | Direction | Limits | Status |
|---|---|---|---|
| Office 365 connector webhook | Into a channel | No longer posts | Retired in May 2026 |
| Workflows webhook | Into a channel or chat | 28 KB per message, POST only | Current way to post |
| Outgoing webhook | From an @mention to your HTTPS URL | Reply within 5 seconds, public channels only | Still documented by Microsoft |
Create a Workflows webhook for a channel
- Open the channel in Microsoft Teams and select More options next to the channel name.
- Select Workflows.
- Pick a template such as
Send webhook alerts to a channel(chat versions likeSend webhook alerts to a chatexist too). - Configure the parameters and select Save.
- Copy the webhook link from the workflow.
Each template sets a different authentication type on the underlying When a Teams webhook request is received trigger, which can accept requests from Anyone, any user in the tenant, or specific users in the tenant. If your workflow is set to Anyone, don't send an authentication token header or the POST fails, while the tenant options require a token.
Using these templates and the Teams trigger doesn't require a premium license, and they work in private channels too when set up in the Workflows app or the Power Automate portal. One operational catch: a workflow belongs to the user who created it rather than the team or channel, so add co-owners right away or it can end up orphaned when its owner leaves.
Preview the payload in a bin before it reaches Teams
Before pointing your script or alert rule at a live channel, point the same code or curl command at a free webhooks.sh bin URL (https://<bin>.webhooks.page/) and open the browser viewer. Check a few things on the captured request:
- The HTTP method is
POST(the Teams trigger doesn't supportGET). - The
Content-Typeheader isapplication/json. - The body is valid JSON with
typeset tomessageandcontentUrlset tonull. - The total body size is under the 28 KB Teams limit.
Once the payload looks right in the viewer, swap the bin URL for your Teams workflow URL. Keep in mind that a webhooks.sh bin always replies with HTTP 200 and its own small JSON ({"ok":true,"delivery_id":"..."}), so it shows you the exact bytes your code sent, not how Teams renders the card.
# 1. Create a free bin (or open view.webhooks.page)
curl -X POST https://webhooks.sh/v1/bins
# 2. Send your card to the bin first, then to the Teams workflow URL
curl -X POST "https://<bin>.webhooks.page/teams" \
-H "Content-Type: application/json" \
-d @card.json
The Adaptive Card JSON Teams expects
The Teams webhook trigger accepts two body schemas: a collection of Adaptive Cards or a single MessageCard. For a Teams Adaptive Card webhook, wrap the card in this envelope: type must always be message, attachments is an array, and each item in attachments needs contentType set to application/vnd.microsoft.card.adaptive, contentUrl set to null, and the card JSON itself inside content.
Legacy MessageCard payloads still render through Workflows, but their interactive HTTP POST action buttons don't work, so use Adaptive Cards whenever you need interactive cards. Text fields in cards take basic Markdown, while HTML is ignored and treated as plain text.
Keep each message under 28 KB. More than four requests a second gets the client connection throttled, so retry with exponential backoff.
{
"type": "message",
"attachments": [
{
"contentType": "application/vnd.microsoft.card.adaptive",
"contentUrl": null,
"content": {
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"type": "AdaptiveCard",
"version": "1.2",
"body": [
{ "type": "TextBlock", "text": "**Deploy finished**: api-gateway is live" }
]
}
}
]
}
Outgoing webhooks: HMAC and a 5-second reply
A Teams outgoing webhook goes the other way: someone @mentions the webhook's name in a public channel and Teams sends a synchronous POST with the message to your HTTPS callback URL. You create one in Teams under Manage team > Apps > Create an outgoing webhook, which gives you a unique HMAC security token that doesn't expire.
Your server has to verify every request and answer fast. Read the Authorization header, which holds HMAC followed by a base64 HMAC-SHA256 signature of the raw request body, computed using the base64-decoded security token. Reply within 5 seconds with a message JSON such as {"type": "message", "text": "This is a reply!"} before the connection times out; the reply appears in the same thread, and any cards you return can only use openURL actions.
If you point an outgoing webhook at a webhooks.sh bin, the bin captures the POST so you can inspect the message JSON Teams sends, but the viewer redacts the Authorization header, and the bin's fixed {"ok":true,"delivery_id":"..."} reply isn't a Teams message, so it can't post a reply in the channel. The wsh CLI doesn't pass your local server's reply back to the sender either, so test outgoing webhook replies and HMAC verification directly against your own public HTTPS server.
import { createHmac, timingSafeEqual } from "node:crypto";
export function isFromTeams(rawBody, authorizationHeader, securityToken) {
const key = Buffer.from(securityToken, "base64");
const expected = "HMAC " + createHmac("sha256", key).update(rawBody).digest("base64");
const got = Buffer.from(authorizationHeader ?? "");
const want = Buffer.from(expected);
return got.length === want.length && timingSafeEqual(got, want);
}
Keep the URL or relay to localhost
A free bin lasts 48 hours and accepts 100 requests a day (up to 100KB per body), which is plenty for checking card JSON before it hits a channel. To keep the same URL for future alert changes, claim the bin with a free Google sign-in before it expires; the timer stops and you keep 30 days of rolling history.
For building a service that receives webhooks, Solo ($12 a month, see pricing) gives you named endpoints on webhooks.host with 250,000 requests per billing period and the wsh CLI (wsh listen <endpoint> --to localhost:3000) to relay live deliveries straight to localhost. And if your flow uses the generic Power Automate HTTP trigger instead of the Teams-specific template, see the Power Automate webhooks guide.
FAQ
How do I create an incoming webhook in Microsoft Teams now?
Use the Workflows app in Teams: select More options next to the channel, select Workflows, pick a template such as Send webhook alerts to a channel, select Save, and copy the webhook link. See Microsoft's guide to add an incoming webhook for template details.
Do old Office 365 connector webhook URLs still work?
No. Microsoft's final retirement of Office 365 connectors rolled out from May 18 to May 22, 2026, so you have to recreate those webhooks with Workflows.
What JSON does a Teams workflow webhook accept?
It accepts either a message envelope with an attachments array of Adaptive Cards (contentType set to application/vnd.microsoft.card.adaptive, contentUrl set to null, and type set to message) or a single MessageCard.
What is the size limit for a Teams webhook message?
28 KB per message. Larger payloads return an error.
Can I change the name or icon of the Teams webhook bot?
No. Every message from a Workflows webhook posts as the Workflows bot, and its name and icon can't be customized.
How do I verify a Teams outgoing webhook?
Base64-decode the security token from Teams, compute a base64 HMAC-SHA256 of the request body with it, and compare that value to the string after HMAC in the Authorization header. Your server then has 5 seconds to return a reply JSON.
Last updated
Try it in 10 seconds.
Create a free bin at view.webhooks.page — no signup, no install. Point your sender at the URL and watch requests land live. Bins expire after 48 hours.